From 301a581e64d9e13b9b0d244e33df6c3d24bd7b10 Mon Sep 17 00:00:00 2001 From: kevinz000 Date: Tue, 29 Aug 2017 09:41:11 -0700 Subject: [PATCH] sync --- code/_onclick/drag_drop.dm | 39 +- code/game/machinery/doors/door.dm | 704 ++++++------ code/game/objects/items/storage/backpack.dm | 1101 +++++++++--------- code/game/objects/items/storage/fancy.dm | 546 ++++----- code/game/objects/items/storage/lockbox.dm | 362 +++--- code/game/objects/items/storage/secure.dm | 394 +++---- code/game/objects/items/storage/storage.dm | 1148 ++++++++++--------- code/game/objects/objs.dm | 444 +++---- code/game/objects/structures/false_walls.dm | 4 +- code/game/objects/structures/grille.dm | 4 +- code/game/turfs/simulated/walls.dm | 4 +- code/modules/recycling/disposal-unit.dm | 3 + code/modules/research/stock_parts.dm | 9 +- 13 files changed, 2388 insertions(+), 2374 deletions(-) diff --git a/code/_onclick/drag_drop.dm b/code/_onclick/drag_drop.dm index 777d52f9ef..e7d5755962 100644 --- a/code/_onclick/drag_drop.dm +++ b/code/_onclick/drag_drop.dm @@ -1,19 +1,20 @@ -/* - MouseDrop: - - Called on the atom you're dragging. In a lot of circumstances we want to use the - recieving object instead, so that's the default action. This allows you to drag - almost anything into a trash can. -*/ -/atom/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) - if(!usr || !over) return - if(over == src) - return usr.client.Click(src, src_location, src_control, params) - if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows - - over.MouseDrop_T(src,usr) - return - -// recieve a mousedrop -/atom/proc/MouseDrop_T(atom/dropping, mob/user) - return +/* + MouseDrop: + + Called on the atom you're dragging. In a lot of circumstances we want to use the + recieving object instead, so that's the default action. This allows you to drag + almost anything into a trash can. +*/ +/atom/MouseDrop(atom/over, src_location, over_location, src_control, over_control, params) + if(!usr || !over) + return + if(over == src) + return usr.client.Click(src, src_location, src_control, params) + if(!Adjacent(usr) || !over.Adjacent(usr)) return // should stop you from dragging through windows + + over.MouseDrop_T(src,usr) + return + +// recieve a mousedrop +/atom/proc/MouseDrop_T(atom/dropping, mob/user) + return diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index f12341d669..65a92c0b1a 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -1,352 +1,352 @@ -/obj/machinery/door - name = "door" - desc = "It opens and closes." - icon = 'icons/obj/doors/Doorint.dmi' - icon_state = "door1" - anchored = TRUE - opacity = 1 - density = TRUE - layer = OPEN_DOOR_LAYER - power_channel = ENVIRON - max_integrity = 350 - armor = list(melee = 30, bullet = 30, laser = 20, energy = 20, bomb = 10, bio = 100, rad = 100, fire = 80, acid = 70) - CanAtmosPass = ATMOS_PASS_DENSITY - flags_1 = PREVENT_CLICK_UNDER_1 - - var/secondsElectrified = 0 - var/shockedby = list() - var/visible = TRUE - var/operating = FALSE - var/glass = FALSE - var/welded = FALSE - var/normalspeed = 1 - var/heat_proof = FALSE // For rglass-windowed airlocks and firedoors - var/emergency = FALSE // Emergency access override - var/sub_door = FALSE // true if it's meant to go under another door. - var/closingLayer = CLOSED_DOOR_LAYER - var/autoclose = FALSE //does it automatically close after some time - var/safe = TRUE //whether the door detects things and mobs in its way and reopen or crushes them. - var/locked = FALSE //whether the door is bolted or not. - var/assemblytype //the type of door frame to drop during deconstruction - var/auto_close //TO BE REMOVED, no longer used, it's just preventing a runtime with a map var edit. - var/datum/effect_system/spark_spread/spark_system - var/damage_deflection = 10 - var/real_explosion_block //ignore this, just use explosion_block - -/obj/machinery/door/New() - ..() - if(density) - layer = CLOSED_DOOR_LAYER //Above most items if closed - else - layer = OPEN_DOOR_LAYER //Under all objects if opened. 2.7 due to tables being at 2.6 - update_freelook_sight() - air_update_turf(1) - GLOB.airlocks += src - spark_system = new /datum/effect_system/spark_spread - spark_system.set_up(2, 1, src) - - //doors only block while dense though so we have to use the proc - real_explosion_block = explosion_block - explosion_block = EXPLOSION_BLOCK_PROC - -/obj/machinery/door/Destroy() - density = FALSE - air_update_turf(1) - update_freelook_sight() - GLOB.airlocks -= src - if(spark_system) - qdel(spark_system) - spark_system = null - return ..() - -//process() - //return - -/obj/machinery/door/CollidedWith(atom/movable/AM) - if(operating || emagged) - return - if(ismob(AM)) - var/mob/B = AM - if((isdrone(B) || iscyborg(B)) && B.stat) - return - if(isliving(AM)) - var/mob/living/M = AM - if(world.time - M.last_bumped <= 10) - return //Can bump-open one airlock per second. This is to prevent shock spam. - M.last_bumped = world.time - if(M.restrained() && !check_access(null)) - return - bumpopen(M) - return - - if(istype(AM, /obj/mecha)) - var/obj/mecha/mecha = AM - if(density) - if(mecha.occupant) - if(world.time - mecha.occupant.last_bumped <= 10) - return - mecha.occupant.last_bumped = world.time - if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access))) - open() - else - do_animate("deny") - return - return - -/obj/machinery/door/Move() - var/turf/T = loc - ..() - move_update_air(T) - -/obj/machinery/door/CanPass(atom/movable/mover, turf/target) - if(istype(mover) && mover.checkpass(PASSGLASS)) - return !opacity - return !density - -/obj/machinery/door/proc/bumpopen(mob/user) - if(operating) - return - src.add_fingerprint(user) - if(!src.requiresID()) - user = null - - if(density && !emagged) - if(allowed(user)) - open() - else - do_animate("deny") - return - - -/obj/machinery/door/attack_ai(mob/user) - return src.attack_hand(user) - -/obj/machinery/door/attack_hand(mob/user) - return try_to_activate_door(user) - - -/obj/machinery/door/attack_tk(mob/user) - if(requiresID() && !allowed(null)) - return - ..() - -/obj/machinery/door/proc/try_to_activate_door(mob/user) - add_fingerprint(user) - if(operating || emagged) - return - if(!requiresID()) - user = null //so allowed(user) always succeeds - if(allowed(user)) - if(density) - open() - else - close() - return - if(density) - do_animate("deny") - -/obj/machinery/door/allowed(mob/M) - if(emergency) - return TRUE - return ..() - -/obj/machinery/door/proc/try_to_weld(obj/item/weldingtool/W, mob/user) - return - -/obj/machinery/door/proc/try_to_crowbar(obj/item/I, mob/user) - return - -/obj/machinery/door/attackby(obj/item/I, mob/user, params) - if(user.a_intent != INTENT_HARM && (istype(I, /obj/item/crowbar) || istype(I, /obj/item/twohanded/fireaxe))) - try_to_crowbar(I, user) - return 1 - else if(istype(I, /obj/item/weldingtool)) - try_to_weld(I, user) - return 1 - else if(!(I.flags_1 & NOBLUDGEON_1) && user.a_intent != INTENT_HARM) - try_to_activate_door(user) - return 1 - return ..() - -/obj/machinery/door/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) - if(damage_flag == "melee" && damage_amount < damage_deflection) - return 0 - . = ..() - -/obj/machinery/door/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) - . = ..() - if(. && obj_integrity > 0) - if(damage_amount >= 10 && prob(30)) - spark_system.start() - -/obj/machinery/door/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) - switch(damage_type) - if(BRUTE) - if(glass) - playsound(loc, 'sound/effects/glasshit.ogg', 90, 1) - else if(damage_amount) - playsound(loc, 'sound/weapons/smash.ogg', 50, 1) - else - playsound(src, 'sound/weapons/tap.ogg', 50, 1) - if(BURN) - playsound(src.loc, 'sound/items/welder.ogg', 100, 1) - -/obj/machinery/door/emp_act(severity) - if(prob(20/severity) && (istype(src, /obj/machinery/door/airlock) || istype(src, /obj/machinery/door/window)) ) - INVOKE_ASYNC(src, .proc/open) - if(prob(40/severity)) - if(secondsElectrified == 0) - secondsElectrified = -1 - shockedby += "\[[time_stamp()]\]EM Pulse" - addtimer(CALLBACK(src, .proc/unelectrify), 300) - ..() - -/obj/machinery/door/proc/unelectrify() - secondsElectrified = 0 - -/obj/machinery/door/update_icon() - if(density) - icon_state = "door1" - else - icon_state = "door0" - -/obj/machinery/door/proc/do_animate(animation) - switch(animation) - if("opening") - if(panel_open) - flick("o_doorc0", src) - else - flick("doorc0", src) - if("closing") - if(panel_open) - flick("o_doorc1", src) - else - flick("doorc1", src) - if("deny") - if(!stat) - flick("door_deny", src) - - -/obj/machinery/door/proc/open() - if(!density) - return 1 - if(operating) - return - operating = TRUE - do_animate("opening") - set_opacity(0) - sleep(5) - density = FALSE - sleep(5) - layer = OPEN_DOOR_LAYER - update_icon() - set_opacity(0) - operating = FALSE - air_update_turf(1) - update_freelook_sight() - if(autoclose) - spawn(autoclose) - close() - return 1 - -/obj/machinery/door/proc/close() - if(density) - return 1 - if(operating) - return - if(safe) - for(var/atom/movable/M in get_turf(src)) - if(M.density && M != src) //something is blocking the door - if(autoclose) - addtimer(CALLBACK(src, .proc/autoclose), 60) - return - operating = TRUE - - do_animate("closing") - layer = closingLayer - sleep(5) - density = TRUE - sleep(5) - update_icon() - if(visible && !glass) - set_opacity(1) - operating = FALSE - air_update_turf(1) - update_freelook_sight() - if(safe) - CheckForMobs() - else - crush() - return 1 - -/obj/machinery/door/proc/CheckForMobs() - if(locate(/mob/living) in get_turf(src)) - sleep(1) - open() - -/obj/machinery/door/proc/crush() - for(var/mob/living/L in get_turf(src)) - L.visible_message("[src] closes on [L], crushing them!", "[src] closes on you and crushes you!") - if(isalien(L)) //For xenos - L.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 1.5) //Xenos go into crit after aproximately the same amount of crushes as humans. - L.emote("roar") - else if(ishuman(L)) //For humans - L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) - L.emote("scream") - L.Knockdown(100) - else if(ismonkey(L)) //For monkeys - L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) - L.Knockdown(100) - else //for simple_animals & borgs - L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) - var/turf/location = get_turf(src) - //add_blood doesn't work for borgs/xenos, but add_blood_floor does. - L.add_splatter_floor(location) - for(var/obj/mecha/M in get_turf(src)) - M.take_damage(DOOR_CRUSH_DAMAGE) - -/obj/machinery/door/proc/autoclose() - if(!QDELETED(src) && !density && !operating && !locked && !welded && autoclose) - close() - -/obj/machinery/door/proc/requiresID() - return 1 - -/obj/machinery/door/proc/hasPower() - return !(stat & NOPOWER) - -/obj/machinery/door/proc/update_freelook_sight() - if(!glass && GLOB.cameranet) - GLOB.cameranet.updateVisibility(src, 0) - -/obj/machinery/door/BlockSuperconductivity() // All non-glass airlocks block heat, this is intended. - if(opacity || heat_proof) - return 1 - return 0 - -/obj/machinery/door/morgue - icon = 'icons/obj/doors/doormorgue.dmi' - -/obj/machinery/door/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - return 0 - -/obj/machinery/door/proc/lock() - return - -/obj/machinery/door/proc/unlock() - return - -/obj/machinery/door/proc/hostile_lockdown(mob/origin) - if(!stat) //So that only powered doors are closed. - close() //Close ALL the doors! - -/obj/machinery/door/proc/disable_lockdown() - if(!stat) //Opens only powered doors. - open() //Open everything! - -/obj/machinery/door/ex_act(severity, target) - //if it blows up a wall it should blow up a door - ..(severity ? max(1, severity - 1) : 0, target) - -/obj/machinery/door/GetExplosionBlock() - return density ? real_explosion_block : 0 +/obj/machinery/door + name = "door" + desc = "It opens and closes." + icon = 'icons/obj/doors/Doorint.dmi' + icon_state = "door1" + anchored = TRUE + opacity = 1 + density = TRUE + layer = OPEN_DOOR_LAYER + power_channel = ENVIRON + max_integrity = 350 + armor = list(melee = 30, bullet = 30, laser = 20, energy = 20, bomb = 10, bio = 100, rad = 100, fire = 80, acid = 70) + CanAtmosPass = ATMOS_PASS_DENSITY + flags_1 = PREVENT_CLICK_UNDER_1 + + var/secondsElectrified = 0 + var/shockedby = list() + var/visible = TRUE + var/operating = FALSE + var/glass = FALSE + var/welded = FALSE + var/normalspeed = 1 + var/heat_proof = FALSE // For rglass-windowed airlocks and firedoors + var/emergency = FALSE // Emergency access override + var/sub_door = FALSE // true if it's meant to go under another door. + var/closingLayer = CLOSED_DOOR_LAYER + var/autoclose = FALSE //does it automatically close after some time + var/safe = TRUE //whether the door detects things and mobs in its way and reopen or crushes them. + var/locked = FALSE //whether the door is bolted or not. + var/assemblytype //the type of door frame to drop during deconstruction + var/auto_close //TO BE REMOVED, no longer used, it's just preventing a runtime with a map var edit. + var/datum/effect_system/spark_spread/spark_system + var/damage_deflection = 10 + var/real_explosion_block //ignore this, just use explosion_block + +/obj/machinery/door/New() + ..() + if(density) + layer = CLOSED_DOOR_LAYER //Above most items if closed + else + layer = OPEN_DOOR_LAYER //Under all objects if opened. 2.7 due to tables being at 2.6 + update_freelook_sight() + air_update_turf(1) + GLOB.airlocks += src + spark_system = new /datum/effect_system/spark_spread + spark_system.set_up(2, 1, src) + + //doors only block while dense though so we have to use the proc + real_explosion_block = explosion_block + explosion_block = EXPLOSION_BLOCK_PROC + +/obj/machinery/door/Destroy() + density = FALSE + air_update_turf(1) + update_freelook_sight() + GLOB.airlocks -= src + if(spark_system) + qdel(spark_system) + spark_system = null + return ..() + +//process() + //return + +/obj/machinery/door/CollidedWith(atom/movable/AM) + if(operating || emagged) + return + if(ismob(AM)) + var/mob/B = AM + if((isdrone(B) || iscyborg(B)) && B.stat) + return + if(isliving(AM)) + var/mob/living/M = AM + if(world.time - M.last_bumped <= 10) + return //Can bump-open one airlock per second. This is to prevent shock spam. + M.last_bumped = world.time + if(M.restrained() && !check_access(null)) + return + bumpopen(M) + return + + if(istype(AM, /obj/mecha)) + var/obj/mecha/mecha = AM + if(density) + if(mecha.occupant) + if(world.time - mecha.occupant.last_bumped <= 10) + return + mecha.occupant.last_bumped = world.time + if(mecha.occupant && (src.allowed(mecha.occupant) || src.check_access_list(mecha.operation_req_access))) + open() + else + do_animate("deny") + return + return + +/obj/machinery/door/Move() + var/turf/T = loc + ..() + move_update_air(T) + +/obj/machinery/door/CanPass(atom/movable/mover, turf/target) + if(istype(mover) && mover.checkpass(PASSGLASS)) + return !opacity + return !density + +/obj/machinery/door/proc/bumpopen(mob/user) + if(operating) + return + src.add_fingerprint(user) + if(!src.requiresID()) + user = null + + if(density && !emagged) + if(allowed(user)) + open() + else + do_animate("deny") + return + + +/obj/machinery/door/attack_ai(mob/user) + return src.attack_hand(user) + +/obj/machinery/door/attack_hand(mob/user) + return try_to_activate_door(user) + + +/obj/machinery/door/attack_tk(mob/user) + if(requiresID() && !allowed(null)) + return + ..() + +/obj/machinery/door/proc/try_to_activate_door(mob/user) + add_fingerprint(user) + if(operating || emagged) + return + if(!requiresID()) + user = null //so allowed(user) always succeeds + if(allowed(user)) + if(density) + open() + else + close() + return + if(density) + do_animate("deny") + +/obj/machinery/door/allowed(mob/M) + if(emergency) + return TRUE + return ..() + +/obj/machinery/door/proc/try_to_weld(obj/item/weldingtool/W, mob/user) + return + +/obj/machinery/door/proc/try_to_crowbar(obj/item/I, mob/user) + return + +/obj/machinery/door/attackby(obj/item/I, mob/user, params) + if(user.a_intent != INTENT_HARM && (istype(I, /obj/item/crowbar) || istype(I, /obj/item/twohanded/fireaxe))) + try_to_crowbar(I, user) + return 1 + else if(istype(I, /obj/item/weldingtool)) + try_to_weld(I, user) + return 1 + else if(!(I.flags_1 & NOBLUDGEON_1) && user.a_intent != INTENT_HARM) + try_to_activate_door(user) + return 1 + return ..() + +/obj/machinery/door/run_obj_armor(damage_amount, damage_type, damage_flag = 0, attack_dir) + if(damage_flag == "melee" && damage_amount < damage_deflection) + return 0 + . = ..() + +/obj/machinery/door/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir) + . = ..() + if(. && obj_integrity > 0) + if(damage_amount >= 10 && prob(30)) + spark_system.start() + +/obj/machinery/door/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) + switch(damage_type) + if(BRUTE) + if(glass) + playsound(loc, 'sound/effects/glasshit.ogg', 90, 1) + else if(damage_amount) + playsound(loc, 'sound/weapons/smash.ogg', 50, 1) + else + playsound(src, 'sound/weapons/tap.ogg', 50, 1) + if(BURN) + playsound(src.loc, 'sound/items/welder.ogg', 100, 1) + +/obj/machinery/door/emp_act(severity) + if(prob(20/severity) && (istype(src, /obj/machinery/door/airlock) || istype(src, /obj/machinery/door/window)) ) + INVOKE_ASYNC(src, .proc/open) + if(prob(40/severity)) + if(secondsElectrified == 0) + secondsElectrified = -1 + shockedby += "\[[time_stamp()]\]EM Pulse" + addtimer(CALLBACK(src, .proc/unelectrify), 300) + ..() + +/obj/machinery/door/proc/unelectrify() + secondsElectrified = 0 + +/obj/machinery/door/update_icon() + if(density) + icon_state = "door1" + else + icon_state = "door0" + +/obj/machinery/door/proc/do_animate(animation) + switch(animation) + if("opening") + if(panel_open) + flick("o_doorc0", src) + else + flick("doorc0", src) + if("closing") + if(panel_open) + flick("o_doorc1", src) + else + flick("doorc1", src) + if("deny") + if(!stat) + flick("door_deny", src) + + +/obj/machinery/door/proc/open() + if(!density) + return 1 + if(operating) + return + operating = TRUE + do_animate("opening") + set_opacity(0) + sleep(5) + density = FALSE + sleep(5) + layer = OPEN_DOOR_LAYER + update_icon() + set_opacity(0) + operating = FALSE + air_update_turf(1) + update_freelook_sight() + if(autoclose) + spawn(autoclose) + close() + return 1 + +/obj/machinery/door/proc/close() + if(density) + return 1 + if(operating) + return + if(safe) + for(var/atom/movable/M in get_turf(src)) + if(M.density && M != src) //something is blocking the door + if(autoclose) + addtimer(CALLBACK(src, .proc/autoclose), 60) + return + operating = TRUE + + do_animate("closing") + layer = closingLayer + sleep(5) + density = TRUE + sleep(5) + update_icon() + if(visible && !glass) + set_opacity(1) + operating = FALSE + air_update_turf(1) + update_freelook_sight() + if(safe) + CheckForMobs() + else + crush() + return 1 + +/obj/machinery/door/proc/CheckForMobs() + if(locate(/mob/living) in get_turf(src)) + sleep(1) + open() + +/obj/machinery/door/proc/crush() + for(var/mob/living/L in get_turf(src)) + L.visible_message("[src] closes on [L], crushing them!", "[src] closes on you and crushes you!") + if(isalien(L)) //For xenos + L.adjustBruteLoss(DOOR_CRUSH_DAMAGE * 1.5) //Xenos go into crit after aproximately the same amount of crushes as humans. + L.emote("roar") + else if(ishuman(L)) //For humans + L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) + L.emote("scream") + L.Knockdown(100) + else if(ismonkey(L)) //For monkeys + L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) + L.Knockdown(100) + else //for simple_animals & borgs + L.adjustBruteLoss(DOOR_CRUSH_DAMAGE) + var/turf/location = get_turf(src) + //add_blood doesn't work for borgs/xenos, but add_blood_floor does. + L.add_splatter_floor(location) + for(var/obj/mecha/M in get_turf(src)) + M.take_damage(DOOR_CRUSH_DAMAGE) + +/obj/machinery/door/proc/autoclose() + if(!QDELETED(src) && !density && !operating && !locked && !welded && autoclose) + close() + +/obj/machinery/door/proc/requiresID() + return 1 + +/obj/machinery/door/proc/hasPower() + return !(stat & NOPOWER) + +/obj/machinery/door/proc/update_freelook_sight() + if(!glass && GLOB.cameranet) + GLOB.cameranet.updateVisibility(src, 0) + +/obj/machinery/door/BlockSuperconductivity() // All non-glass airlocks block heat, this is intended. + if(opacity || heat_proof) + return 1 + return 0 + +/obj/machinery/door/morgue + icon = 'icons/obj/doors/doormorgue.dmi' + +/obj/machinery/door/get_dumping_location(obj/item/storage/source,mob/user) + return null + +/obj/machinery/door/proc/lock() + return + +/obj/machinery/door/proc/unlock() + return + +/obj/machinery/door/proc/hostile_lockdown(mob/origin) + if(!stat) //So that only powered doors are closed. + close() //Close ALL the doors! + +/obj/machinery/door/proc/disable_lockdown() + if(!stat) //Opens only powered doors. + open() //Open everything! + +/obj/machinery/door/ex_act(severity, target) + //if it blows up a wall it should blow up a door + ..(severity ? max(1, severity - 1) : 0, target) + +/obj/machinery/door/GetExplosionBlock() + return density ? real_explosion_block : 0 diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 2446c73cbd..fe89f42338 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -1,550 +1,551 @@ -/* Backpacks - * Contains: - * Backpack - * Backpack Types - * Satchel Types - */ - -/* - * Backpack - */ - -/obj/item/storage/backpack - name = "backpack" - desc = "You wear this on your back and put items into it." - icon_state = "backpack" - item_state = "backpack" - lefthand_file = 'icons/mob/inhands/equipment/backpack_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi' - w_class = WEIGHT_CLASS_BULKY - slot_flags = SLOT_BACK //ERROOOOO - max_w_class = WEIGHT_CLASS_NORMAL - max_combined_w_class = 21 - storage_slots = 21 - resistance_flags = 0 - max_integrity = 300 - -/* - * Backpack Types - */ - -/obj/item/storage/backpack/old - max_combined_w_class = 12 - -/obj/item/storage/backpack/holding - name = "bag of holding" - desc = "A backpack that opens into a localized pocket of Blue Space." - origin_tech = "bluespace=5;materials=4;engineering=4;plasmatech=5" - icon_state = "holdingpack" - item_state = "holdingpack" - max_w_class = WEIGHT_CLASS_GIGANTIC - max_combined_w_class = 35 - resistance_flags = FIRE_PROOF - var/pshoom = 'sound/items/pshoom.ogg' - var/alt_sound = 'sound/items/pshoom_2.ogg' - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 60, acid = 50) - - -/obj/item/storage/backpack/holding/suicide_act(mob/living/user) - user.visible_message("[user] is jumping into [src]! It looks like [user.p_theyre()] trying to commit suicide.") - user.drop_item() - user.Stun(100, ignore_canstun = TRUE) - sleep(20) - playsound(src, "rustle", 50, 1, -5) - qdel(user) - return - -/obj/item/storage/backpack/holding/content_can_dump(atom/dest_object, mob/user) - if(Adjacent(user)) - if(get_dist(user, dest_object) < 8) - if(dest_object.storage_contents_dump_act(src, user)) - if(alt_sound && prob(1)) - playsound(src, alt_sound, 40, 1) - else - playsound(src, pshoom, 40, 1) - user.Beam(dest_object,icon_state="rped_upgrade",time=5) - return 1 - to_chat(user, "The [src.name] buzzes.") - playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0) - return 0 - -/obj/item/storage/backpack/holding/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) - if((istype(W, /obj/item/storage/backpack/holding) || count_by_type(W.GetAllContents(), /obj/item/storage/backpack/holding))) - var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [name]?", "Proceed", "Abort") - if(safety == "Abort" || !in_range(src, user) || !src || !W || user.incapacitated()) - return - investigate_log("has become a singularity. Caused by [user.key]", INVESTIGATE_SINGULO) - to_chat(user, "The Bluespace interfaces of the two devices catastrophically malfunction!") - qdel(W) - var/obj/singularity/singulo = new /obj/singularity (get_turf(src)) - singulo.energy = 300 //should make it a bit bigger~ - message_admins("[key_name_admin(user)] detonated a bag of holding") - log_game("[key_name(user)] detonated a bag of holding") - qdel(src) - singulo.process() - return - . = ..() - -/obj/item/storage/backpack/holding/singularity_act(current_size) - var/dist = max((current_size - 2),1) - explosion(src.loc,(dist),(dist*2),(dist*4)) - return - - -/obj/item/storage/backpack/santabag - name = "Santa's Gift Bag" - desc = "Space Santa uses this to deliver toys to all the nice children in space in Christmas! Wow, it's pretty big!" - icon_state = "giftbag0" - item_state = "giftbag" - w_class = WEIGHT_CLASS_BULKY - max_w_class = WEIGHT_CLASS_NORMAL - max_combined_w_class = 60 - -/obj/item/storage/backpack/santabag/suicide_act(mob/user) - user.visible_message("[user] places [src] over their head and pulls it tight! It looks like they aren't in the Christmas spirit...") - return (OXYLOSS) - -/obj/item/storage/backpack/cultpack - name = "trophy rack" - desc = "It's useful for both carrying extra gear and proudly declaring your insanity." - icon_state = "cultpack" - item_state = "backpack" - -/obj/item/storage/backpack/clown - name = "Giggles von Honkerton" - desc = "It's a backpack made by Honk! Co." - icon_state = "clownpack" - item_state = "clownpack" - -/obj/item/storage/backpack/explorer - name = "explorer bag" - desc = "A robust backpack for stashing your loot." - icon_state = "explorerpack" - item_state = "explorerpack" - -/obj/item/storage/backpack/mime - name = "Parcel Parceaux" - desc = "A silent backpack made for those silent workers. Silence Co." - icon_state = "mimepack" - item_state = "mimepack" - -/obj/item/storage/backpack/medic - name = "medical backpack" - desc = "It's a backpack especially designed for use in a sterile environment." - icon_state = "medicalpack" - item_state = "medicalpack" - -/obj/item/storage/backpack/security - name = "security backpack" - desc = "It's a very robust backpack." - icon_state = "securitypack" - item_state = "securitypack" - -/obj/item/storage/backpack/captain - name = "captain's backpack" - desc = "It's a special backpack made exclusively for Nanotrasen officers." - icon_state = "captainpack" - item_state = "captainpack" - resistance_flags = 0 - -/obj/item/storage/backpack/industrial - name = "industrial backpack" - desc = "It's a tough backpack for the daily grind of station life." - icon_state = "engiepack" - item_state = "engiepack" - resistance_flags = FIRE_PROOF - -/obj/item/storage/backpack/botany - name = "botany backpack" - desc = "It's a backpack made of all-natural fibers." - icon_state = "botpack" - item_state = "botpack" - -/obj/item/storage/backpack/chemistry - name = "chemistry backpack" - desc = "A backpack specially designed to repel stains and hazardous liquids." - icon_state = "chempack" - item_state = "chempack" - -/obj/item/storage/backpack/genetics - name = "genetics backpack" - desc = "A bag designed to be super tough, just in case someone hulks out on you." - icon_state = "genepack" - item_state = "genepack" - -/obj/item/storage/backpack/science - name = "science backpack" - desc = "A specially designed backpack. It's fire resistant and smells vaguely of plasma." - icon_state = "toxpack" - item_state = "toxpack" - resistance_flags = 0 - -/obj/item/storage/backpack/virology - name = "virology backpack" - desc = "A backpack made of hypo-allergenic fibers. It's designed to help prevent the spread of disease. Smells like monkey." - icon_state = "viropack" - item_state = "viropack" - - -/* - * Satchel Types - */ - -/obj/item/storage/backpack/satchel - name = "satchel" - desc = "A trendy looking satchel." - icon_state = "satchel-norm" - species_exception = list(/datum/species/angel) //satchels can be equipped since they are on the side, not back - -/obj/item/storage/backpack/satchel/leather - name = "leather satchel" - desc = "It's a very fancy satchel made with fine leather." - icon_state = "satchel" - resistance_flags = 0 - -/obj/item/storage/backpack/satchel/leather/withwallet/PopulateContents() - new /obj/item/storage/wallet/random(src) - -/obj/item/storage/backpack/satchel/eng - name = "industrial satchel" - desc = "A tough satchel with extra pockets." - icon_state = "satchel-eng" - item_state = "engiepack" - resistance_flags = 0 - -/obj/item/storage/backpack/satchel/med - name = "medical satchel" - desc = "A sterile satchel used in medical departments." - icon_state = "satchel-med" - item_state = "medicalpack" - -/obj/item/storage/backpack/satchel/vir - name = "virologist satchel" - desc = "A sterile satchel with virologist colours." - icon_state = "satchel-vir" - item_state = "satchel-vir" - -/obj/item/storage/backpack/satchel/chem - name = "chemist satchel" - desc = "A sterile satchel with chemist colours." - icon_state = "satchel-chem" - item_state = "satchel-chem" - -/obj/item/storage/backpack/satchel/gen - name = "geneticist satchel" - desc = "A sterile satchel with geneticist colours." - icon_state = "satchel-gen" - item_state = "satchel-gen" - -/obj/item/storage/backpack/satchel/tox - name = "scientist satchel" - desc = "Useful for holding research materials." - icon_state = "satchel-tox" - item_state = "satchel-tox" - resistance_flags = 0 - -/obj/item/storage/backpack/satchel/hyd - name = "botanist satchel" - desc = "A satchel made of all natural fibers." - icon_state = "satchel-hyd" - item_state = "satchel-hyd" - -/obj/item/storage/backpack/satchel/sec - name = "security satchel" - desc = "A robust satchel for security related needs." - icon_state = "satchel-sec" - item_state = "securitypack" - -/obj/item/storage/backpack/satchel/explorer - name = "explorer satchel" - desc = "A robust satchel for stashing your loot." - icon_state = "satchel-explorer" - item_state = "securitypack" - -/obj/item/storage/backpack/satchel/cap - name = "captain's satchel" - desc = "An exclusive satchel for Nanotrasen officers." - icon_state = "satchel-cap" - item_state = "captainpack" - resistance_flags = 0 - -/obj/item/storage/backpack/satchel/flat - name = "smuggler's satchel" - desc = "A very slim satchel that can easily fit into tight spaces." - icon_state = "satchel-flat" - w_class = WEIGHT_CLASS_NORMAL //Can fit in backpacks itself. - max_combined_w_class = 15 - level = 1 - cant_hold = list(/obj/item/storage/backpack/satchel/flat) //muh recursive backpacks - -/obj/item/storage/backpack/satchel/flat/hide(var/intact) - if(intact) - invisibility = INVISIBILITY_MAXIMUM - anchored = TRUE //otherwise you can start pulling, cover it, and drag around an invisible backpack. - icon_state = "[initial(icon_state)]2" - else - invisibility = initial(invisibility) - anchored = FALSE - icon_state = initial(icon_state) - -/obj/item/storage/backpack/satchel/flat/Initialize(mapload) - ..() - SSpersistence.new_secret_satchels += src - -/obj/item/storage/backpack/satchel/flat/PopulateContents() - new /obj/item/stack/tile/plasteel(src) - new /obj/item/crowbar(src) - -/obj/item/storage/backpack/satchel/flat/Destroy() - SSpersistence.new_secret_satchels -= src - return ..() - -/obj/item/storage/backpack/satchel/flat/secret - var/list/reward_one_of_these = list() //Intended for map editing - var/list/reward_all_of_these = list() //use paths! - var/revealed = 0 - -/obj/item/storage/backpack/satchel/flat/secret/Initialize() - ..() - - if(isfloorturf(loc) && !istype(loc, /turf/open/floor/plating/)) - hide(1) - -/obj/item/storage/backpack/satchel/flat/secret/hide(intact) - ..() - if(!intact && !revealed) - if(reward_one_of_these.len > 0) - var/reward = pick(reward_one_of_these) - new reward(src) - for(var/R in reward_all_of_these) - new R(src) - revealed = 1 - -/obj/item/storage/backpack/duffelbag - name = "duffel bag" - desc = "A large duffel bag for holding extra things." - icon_state = "duffel" - item_state = "duffel" - slowdown = 1 - max_combined_w_class = 30 - -/obj/item/storage/backpack/duffelbag/captain - name = "captain's duffel bag" - desc = "A large duffel bag for holding extra captainly goods." - icon_state = "duffel-captain" - item_state = "duffel-captain" - resistance_flags = 0 - -/obj/item/storage/backpack/duffelbag/med - name = "medical duffel bag" - desc = "A large duffel bag for holding extra medical supplies." - icon_state = "duffel-med" - item_state = "duffel-med" - -/obj/item/storage/backpack/duffelbag/med/surgery - name = "surgical duffel bag" - desc = "A large duffel bag for holding extra medical supplies - this one seems to be designed for holding surgical tools." - -/obj/item/storage/backpack/duffelbag/med/surgery/PopulateContents() - new /obj/item/scalpel(src) - new /obj/item/hemostat(src) - new /obj/item/retractor(src) - new /obj/item/circular_saw(src) - new /obj/item/surgicaldrill(src) - new /obj/item/cautery(src) - new /obj/item/surgical_drapes(src) - new /obj/item/clothing/mask/surgical(src) - new /obj/item/razor(src) - -/obj/item/storage/backpack/duffelbag/sec - name = "security duffel bag" - desc = "A large duffel bag for holding extra security supplies and ammunition." - icon_state = "duffel-sec" - item_state = "duffel-sec" - -/obj/item/storage/backpack/duffelbag/sec/surgery - name = "surgical duffel bag" - desc = "A large duffel bag for holding extra supplies - this one has a material inlay with space for various sharp-looking tools." - -/obj/item/storage/backpack/duffelbag/sec/surgery/PopulateContents() - new /obj/item/scalpel(src) - new /obj/item/hemostat(src) - new /obj/item/retractor(src) - new /obj/item/circular_saw(src) - new /obj/item/surgicaldrill(src) - new /obj/item/cautery(src) - new /obj/item/surgical_drapes(src) - new /obj/item/clothing/mask/surgical(src) - -/obj/item/storage/backpack/duffelbag/engineering - name = "industrial duffel bag" - desc = "A large duffel bag for holding extra tools and supplies." - icon_state = "duffel-eng" - item_state = "duffel-eng" - resistance_flags = 0 - -/obj/item/storage/backpack/duffelbag/drone - name = "drone duffel bag" - desc = "A large duffel bag for holding tools and hats." - icon_state = "duffel-drone" - item_state = "duffel-drone" - resistance_flags = FIRE_PROOF - -/obj/item/storage/backpack/duffelbag/drone/PopulateContents() - new /obj/item/screwdriver(src) - new /obj/item/wrench(src) - new /obj/item/weldingtool(src) - new /obj/item/crowbar(src) - new /obj/item/stack/cable_coil/random(src) - new /obj/item/wirecutters(src) - new /obj/item/device/multitool(src) - -/obj/item/storage/backpack/duffelbag/clown - name = "clown's duffel bag" - desc = "A large duffel bag for holding lots of funny gags!" - icon_state = "duffel-clown" - item_state = "duffel-clown" - -/obj/item/storage/backpack/duffelbag/clown/cream_pie/PopulateContents() - for(var/i in 1 to 10) - new /obj/item/reagent_containers/food/snacks/pie/cream(src) - -/obj/item/storage/backpack/duffelbag/syndie - name = "suspicious looking duffel bag" - desc = "A large duffel bag for holding extra tactical supplies." - icon_state = "duffel-syndie" - item_state = "duffel-syndie" - origin_tech = "syndicate=1" - silent = 1 - slowdown = 0 - -/obj/item/storage/backpack/duffelbag/syndie/hitman - desc = "A large duffel bag for holding extra things. There is a NanoTrasen logo on the back." - icon_state = "duffel-syndieammo" - item_state = "duffel-syndieammo" - -/obj/item/storage/backpack/duffelbag/syndie/hitman/PopulateContents() - new /obj/item/clothing/under/lawyer/blacksuit(src) - new /obj/item/clothing/accessory/waistcoat(src) - new /obj/item/clothing/suit/toggle/lawyer/black(src) - new /obj/item/clothing/shoes/laceup(src) - new /obj/item/clothing/gloves/color/black(src) - new /obj/item/clothing/glasses/sunglasses(src) - new /obj/item/clothing/head/fedora(src) - -/obj/item/storage/backpack/duffelbag/syndie/med - name = "medical duffel bag" - desc = "A large duffel bag for holding extra tactical medical supplies." - icon_state = "duffel-syndiemed" - item_state = "duffel-syndiemed" - -/obj/item/storage/backpack/duffelbag/syndie/surgery - name = "surgery duffel bag" - desc = "A suspicious looking duffel bag for holding surgery tools." - icon_state = "duffel-syndiemed" - item_state = "duffel-syndiemed" - -/obj/item/storage/backpack/duffelbag/syndie/surgery/PopulateContents() - new /obj/item/scalpel(src) - new /obj/item/hemostat(src) - new /obj/item/retractor(src) - new /obj/item/circular_saw(src) - new /obj/item/surgicaldrill(src) - new /obj/item/cautery(src) - new /obj/item/surgical_drapes(src) - new /obj/item/clothing/suit/straight_jacket(src) - new /obj/item/clothing/mask/muzzle(src) - new /obj/item/device/mmi/syndie(src) - -/obj/item/storage/backpack/duffelbag/syndie/ammo - name = "ammunition duffel bag" - desc = "A large duffel bag for holding extra weapons ammunition and supplies." - icon_state = "duffel-syndieammo" - item_state = "duffel-syndieammo" - -/obj/item/storage/backpack/duffelbag/syndie/ammo/shotgun - desc = "A large duffel bag, packed to the brim with Bulldog shotgun ammo." - -/obj/item/storage/backpack/duffelbag/syndie/ammo/shotgun/PopulateContents() - for(var/i in 1 to 6) - new /obj/item/ammo_box/magazine/m12g(src) - new /obj/item/ammo_box/magazine/m12g/buckshot(src) - new /obj/item/ammo_box/magazine/m12g/slug(src) - new /obj/item/ammo_box/magazine/m12g/dragon(src) - -/obj/item/storage/backpack/duffelbag/syndie/ammo/smg - desc = "A large duffel bag, packed to the brim with C20r magazines." - -/obj/item/storage/backpack/duffelbag/syndie/ammo/smg/PopulateContents() - for(var/i in 1 to 9) - new /obj/item/ammo_box/magazine/smgm45(src) - -/obj/item/storage/backpack/duffelbag/syndie/c20rbundle - desc = "A large duffel bag containing a C20r, some magazines, and a cheap looking suppressor." - -/obj/item/storage/backpack/duffelbag/syndie/c20rbundle/PopulateContents() - new /obj/item/ammo_box/magazine/smgm45(src) - new /obj/item/ammo_box/magazine/smgm45(src) - new /obj/item/gun/ballistic/automatic/c20r(src) - new /obj/item/suppressor/specialoffer(src) - -/obj/item/storage/backpack/duffelbag/syndie/bulldogbundle - desc = "A large duffel bag containing a Bulldog, several drums, and a collapsed hardsuit." - -/obj/item/storage/backpack/duffelbag/syndie/bulldogbundle/PopulateContents() - new /obj/item/ammo_box/magazine/m12g(src) - new /obj/item/gun/ballistic/automatic/shotgun/bulldog(src) - new /obj/item/ammo_box/magazine/m12g/buckshot(src) - new /obj/item/clothing/glasses/thermal/syndi(src) - -/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle - desc = "A large duffel bag containing a medical equipment, a Donksoft machine gun, a big jumbo box of darts, and a knock-off pair of magboots." - -/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle/PopulateContents() - new /obj/item/clothing/shoes/magboots/syndie(src) - new /obj/item/storage/firstaid/tactical(src) - new /obj/item/gun/ballistic/automatic/l6_saw/toy(src) - new /obj/item/ammo_box/foambox/riot(src) - -/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle - desc = "A large duffel bag containing a medical equipment, a Donksoft machine gun, a big jumbo box of darts, and a knock-off pair of magboots." - -/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle/PopulateContents() - new /obj/item/clothing/shoes/magboots/syndie(src) - new /obj/item/storage/firstaid/tactical(src) - new /obj/item/gun/ballistic/automatic/l6_saw/toy(src) - new /obj/item/ammo_box/foambox/riot(src) - -/obj/item/storage/backpack/duffelbag/syndie/med/bioterrorbundle - desc = "A large duffel bag containing a deadly chemicals, a chemical spray, chemical grenade, a Donksoft assault rifle, riot grade darts, a minature syringe gun, and a box of syringes" - -/obj/item/storage/backpack/duffelbag/syndie/med/bioterrorbundle/PopulateContents() - new /obj/item/reagent_containers/spray/chemsprayer/bioterror(src) - new /obj/item/storage/box/syndie_kit/chemical(src) - new /obj/item/gun/syringe/syndicate(src) - new /obj/item/gun/ballistic/automatic/c20r/toy(src) - new /obj/item/storage/box/syringes(src) - new /obj/item/ammo_box/foambox/riot(src) - new /obj/item/grenade/chem_grenade/bioterrorfoam(src) - -/obj/item/storage/backpack/duffelbag/syndie/c4/PopulateContents() - for(var/i in 1 to 10) - new /obj/item/grenade/plastic/c4(src) - -/obj/item/storage/backpack/duffelbag/syndie/x4/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/grenade/plastic/x4(src) - -/obj/item/storage/backpack/duffelbag/syndie/firestarter - desc = "A large duffel bag containing New Russian pyro backpack sprayer, a pistol, a pipebomb, fireproof hardsuit, ammo, and other equipment." - -/obj/item/storage/backpack/duffelbag/syndie/firestarter/PopulateContents() - new /obj/item/clothing/under/syndicate/soviet(src) - new /obj/item/watertank/operator(src) - new /obj/item/clothing/suit/space/hardsuit/syndi/elite(src) - new /obj/item/gun/ballistic/automatic/pistol/APS(src) - new /obj/item/ammo_box/magazine/pistolm9mm(src) - new /obj/item/ammo_box/magazine/pistolm9mm(src) - new /obj/item/reagent_containers/food/drinks/bottle/vodka/badminka(src) - new /obj/item/reagent_containers/syringe/stimulants(src) - new /obj/item/grenade/syndieminibomb(src) +/* Backpacks + * Contains: + * Backpack + * Backpack Types + * Satchel Types + */ + +/* + * Backpack + */ + +/obj/item/storage/backpack + name = "backpack" + desc = "You wear this on your back and put items into it." + icon_state = "backpack" + item_state = "backpack" + lefthand_file = 'icons/mob/inhands/equipment/backpack_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi' + w_class = WEIGHT_CLASS_BULKY + slot_flags = SLOT_BACK //ERROOOOO + max_w_class = WEIGHT_CLASS_NORMAL + max_combined_w_class = 21 + storage_slots = 21 + resistance_flags = 0 + max_integrity = 300 + +/* + * Backpack Types + */ + +/obj/item/storage/backpack/old + max_combined_w_class = 12 + +/obj/item/storage/backpack/holding + name = "bag of holding" + desc = "A backpack that opens into a localized pocket of Blue Space." + origin_tech = "bluespace=5;materials=4;engineering=4;plasmatech=5" + icon_state = "holdingpack" + item_state = "holdingpack" + max_w_class = WEIGHT_CLASS_GIGANTIC + max_combined_w_class = 35 + resistance_flags = FIRE_PROOF + var/pshoom = 'sound/items/pshoom.ogg' + var/alt_sound = 'sound/items/pshoom_2.ogg' + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 60, acid = 50) + + +/obj/item/storage/backpack/holding/suicide_act(mob/living/user) + user.visible_message("[user] is jumping into [src]! It looks like [user.p_theyre()] trying to commit suicide.") + user.drop_item() + user.Stun(100, ignore_canstun = TRUE) + sleep(20) + playsound(src, "rustle", 50, 1, -5) + qdel(user) + return + +/obj/item/storage/backpack/holding/dump_content_at(atom/dest_object, mob/user) + if(Adjacent(user)) + var/atom/dumping_location = dest_object.get_dumping_location() + if(get_dist(user, dumping_location) < 8) + if(dumping_location.storage_contents_dump_act(src, user)) + if(alt_sound && prob(1)) + playsound(src, alt_sound, 40, 1) + else + playsound(src, pshoom, 40, 1) + user.Beam(dumping_location,icon_state="rped_upgrade",time=5) + return 1 + to_chat(user, "The [src.name] buzzes.") + playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0) + return 0 + +/obj/item/storage/backpack/holding/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) + if((istype(W, /obj/item/storage/backpack/holding) || count_by_type(W.GetAllContents(), /obj/item/storage/backpack/holding))) + var/safety = alert(user, "Doing this will have extremely dire consequences for the station and its crew. Be sure you know what you're doing.", "Put in [name]?", "Proceed", "Abort") + if(safety == "Abort" || !in_range(src, user) || !src || !W || user.incapacitated()) + return + investigate_log("has become a singularity. Caused by [user.key]", INVESTIGATE_SINGULO) + to_chat(user, "The Bluespace interfaces of the two devices catastrophically malfunction!") + qdel(W) + var/obj/singularity/singulo = new /obj/singularity (get_turf(src)) + singulo.energy = 300 //should make it a bit bigger~ + message_admins("[key_name_admin(user)] detonated a bag of holding") + log_game("[key_name(user)] detonated a bag of holding") + qdel(src) + singulo.process() + return + . = ..() + +/obj/item/storage/backpack/holding/singularity_act(current_size) + var/dist = max((current_size - 2),1) + explosion(src.loc,(dist),(dist*2),(dist*4)) + return + + +/obj/item/storage/backpack/santabag + name = "Santa's Gift Bag" + desc = "Space Santa uses this to deliver toys to all the nice children in space in Christmas! Wow, it's pretty big!" + icon_state = "giftbag0" + item_state = "giftbag" + w_class = WEIGHT_CLASS_BULKY + max_w_class = WEIGHT_CLASS_NORMAL + max_combined_w_class = 60 + +/obj/item/storage/backpack/santabag/suicide_act(mob/user) + user.visible_message("[user] places [src] over their head and pulls it tight! It looks like they aren't in the Christmas spirit...") + return (OXYLOSS) + +/obj/item/storage/backpack/cultpack + name = "trophy rack" + desc = "It's useful for both carrying extra gear and proudly declaring your insanity." + icon_state = "cultpack" + item_state = "backpack" + +/obj/item/storage/backpack/clown + name = "Giggles von Honkerton" + desc = "It's a backpack made by Honk! Co." + icon_state = "clownpack" + item_state = "clownpack" + +/obj/item/storage/backpack/explorer + name = "explorer bag" + desc = "A robust backpack for stashing your loot." + icon_state = "explorerpack" + item_state = "explorerpack" + +/obj/item/storage/backpack/mime + name = "Parcel Parceaux" + desc = "A silent backpack made for those silent workers. Silence Co." + icon_state = "mimepack" + item_state = "mimepack" + +/obj/item/storage/backpack/medic + name = "medical backpack" + desc = "It's a backpack especially designed for use in a sterile environment." + icon_state = "medicalpack" + item_state = "medicalpack" + +/obj/item/storage/backpack/security + name = "security backpack" + desc = "It's a very robust backpack." + icon_state = "securitypack" + item_state = "securitypack" + +/obj/item/storage/backpack/captain + name = "captain's backpack" + desc = "It's a special backpack made exclusively for Nanotrasen officers." + icon_state = "captainpack" + item_state = "captainpack" + resistance_flags = 0 + +/obj/item/storage/backpack/industrial + name = "industrial backpack" + desc = "It's a tough backpack for the daily grind of station life." + icon_state = "engiepack" + item_state = "engiepack" + resistance_flags = FIRE_PROOF + +/obj/item/storage/backpack/botany + name = "botany backpack" + desc = "It's a backpack made of all-natural fibers." + icon_state = "botpack" + item_state = "botpack" + +/obj/item/storage/backpack/chemistry + name = "chemistry backpack" + desc = "A backpack specially designed to repel stains and hazardous liquids." + icon_state = "chempack" + item_state = "chempack" + +/obj/item/storage/backpack/genetics + name = "genetics backpack" + desc = "A bag designed to be super tough, just in case someone hulks out on you." + icon_state = "genepack" + item_state = "genepack" + +/obj/item/storage/backpack/science + name = "science backpack" + desc = "A specially designed backpack. It's fire resistant and smells vaguely of plasma." + icon_state = "toxpack" + item_state = "toxpack" + resistance_flags = 0 + +/obj/item/storage/backpack/virology + name = "virology backpack" + desc = "A backpack made of hypo-allergenic fibers. It's designed to help prevent the spread of disease. Smells like monkey." + icon_state = "viropack" + item_state = "viropack" + + +/* + * Satchel Types + */ + +/obj/item/storage/backpack/satchel + name = "satchel" + desc = "A trendy looking satchel." + icon_state = "satchel-norm" + species_exception = list(/datum/species/angel) //satchels can be equipped since they are on the side, not back + +/obj/item/storage/backpack/satchel/leather + name = "leather satchel" + desc = "It's a very fancy satchel made with fine leather." + icon_state = "satchel" + resistance_flags = 0 + +/obj/item/storage/backpack/satchel/leather/withwallet/PopulateContents() + new /obj/item/storage/wallet/random(src) + +/obj/item/storage/backpack/satchel/eng + name = "industrial satchel" + desc = "A tough satchel with extra pockets." + icon_state = "satchel-eng" + item_state = "engiepack" + resistance_flags = 0 + +/obj/item/storage/backpack/satchel/med + name = "medical satchel" + desc = "A sterile satchel used in medical departments." + icon_state = "satchel-med" + item_state = "medicalpack" + +/obj/item/storage/backpack/satchel/vir + name = "virologist satchel" + desc = "A sterile satchel with virologist colours." + icon_state = "satchel-vir" + item_state = "satchel-vir" + +/obj/item/storage/backpack/satchel/chem + name = "chemist satchel" + desc = "A sterile satchel with chemist colours." + icon_state = "satchel-chem" + item_state = "satchel-chem" + +/obj/item/storage/backpack/satchel/gen + name = "geneticist satchel" + desc = "A sterile satchel with geneticist colours." + icon_state = "satchel-gen" + item_state = "satchel-gen" + +/obj/item/storage/backpack/satchel/tox + name = "scientist satchel" + desc = "Useful for holding research materials." + icon_state = "satchel-tox" + item_state = "satchel-tox" + resistance_flags = 0 + +/obj/item/storage/backpack/satchel/hyd + name = "botanist satchel" + desc = "A satchel made of all natural fibers." + icon_state = "satchel-hyd" + item_state = "satchel-hyd" + +/obj/item/storage/backpack/satchel/sec + name = "security satchel" + desc = "A robust satchel for security related needs." + icon_state = "satchel-sec" + item_state = "securitypack" + +/obj/item/storage/backpack/satchel/explorer + name = "explorer satchel" + desc = "A robust satchel for stashing your loot." + icon_state = "satchel-explorer" + item_state = "securitypack" + +/obj/item/storage/backpack/satchel/cap + name = "captain's satchel" + desc = "An exclusive satchel for Nanotrasen officers." + icon_state = "satchel-cap" + item_state = "captainpack" + resistance_flags = 0 + +/obj/item/storage/backpack/satchel/flat + name = "smuggler's satchel" + desc = "A very slim satchel that can easily fit into tight spaces." + icon_state = "satchel-flat" + w_class = WEIGHT_CLASS_NORMAL //Can fit in backpacks itself. + max_combined_w_class = 15 + level = 1 + cant_hold = list(/obj/item/storage/backpack/satchel/flat) //muh recursive backpacks + +/obj/item/storage/backpack/satchel/flat/hide(var/intact) + if(intact) + invisibility = INVISIBILITY_MAXIMUM + anchored = TRUE //otherwise you can start pulling, cover it, and drag around an invisible backpack. + icon_state = "[initial(icon_state)]2" + else + invisibility = initial(invisibility) + anchored = FALSE + icon_state = initial(icon_state) + +/obj/item/storage/backpack/satchel/flat/Initialize(mapload) + ..() + SSpersistence.new_secret_satchels += src + +/obj/item/storage/backpack/satchel/flat/PopulateContents() + new /obj/item/stack/tile/plasteel(src) + new /obj/item/crowbar(src) + +/obj/item/storage/backpack/satchel/flat/Destroy() + SSpersistence.new_secret_satchels -= src + return ..() + +/obj/item/storage/backpack/satchel/flat/secret + var/list/reward_one_of_these = list() //Intended for map editing + var/list/reward_all_of_these = list() //use paths! + var/revealed = 0 + +/obj/item/storage/backpack/satchel/flat/secret/Initialize() + ..() + + if(isfloorturf(loc) && !istype(loc, /turf/open/floor/plating/)) + hide(1) + +/obj/item/storage/backpack/satchel/flat/secret/hide(intact) + ..() + if(!intact && !revealed) + if(reward_one_of_these.len > 0) + var/reward = pick(reward_one_of_these) + new reward(src) + for(var/R in reward_all_of_these) + new R(src) + revealed = 1 + +/obj/item/storage/backpack/duffelbag + name = "duffel bag" + desc = "A large duffel bag for holding extra things." + icon_state = "duffel" + item_state = "duffel" + slowdown = 1 + max_combined_w_class = 30 + +/obj/item/storage/backpack/duffelbag/captain + name = "captain's duffel bag" + desc = "A large duffel bag for holding extra captainly goods." + icon_state = "duffel-captain" + item_state = "duffel-captain" + resistance_flags = 0 + +/obj/item/storage/backpack/duffelbag/med + name = "medical duffel bag" + desc = "A large duffel bag for holding extra medical supplies." + icon_state = "duffel-med" + item_state = "duffel-med" + +/obj/item/storage/backpack/duffelbag/med/surgery + name = "surgical duffel bag" + desc = "A large duffel bag for holding extra medical supplies - this one seems to be designed for holding surgical tools." + +/obj/item/storage/backpack/duffelbag/med/surgery/PopulateContents() + new /obj/item/scalpel(src) + new /obj/item/hemostat(src) + new /obj/item/retractor(src) + new /obj/item/circular_saw(src) + new /obj/item/surgicaldrill(src) + new /obj/item/cautery(src) + new /obj/item/surgical_drapes(src) + new /obj/item/clothing/mask/surgical(src) + new /obj/item/razor(src) + +/obj/item/storage/backpack/duffelbag/sec + name = "security duffel bag" + desc = "A large duffel bag for holding extra security supplies and ammunition." + icon_state = "duffel-sec" + item_state = "duffel-sec" + +/obj/item/storage/backpack/duffelbag/sec/surgery + name = "surgical duffel bag" + desc = "A large duffel bag for holding extra supplies - this one has a material inlay with space for various sharp-looking tools." + +/obj/item/storage/backpack/duffelbag/sec/surgery/PopulateContents() + new /obj/item/scalpel(src) + new /obj/item/hemostat(src) + new /obj/item/retractor(src) + new /obj/item/circular_saw(src) + new /obj/item/surgicaldrill(src) + new /obj/item/cautery(src) + new /obj/item/surgical_drapes(src) + new /obj/item/clothing/mask/surgical(src) + +/obj/item/storage/backpack/duffelbag/engineering + name = "industrial duffel bag" + desc = "A large duffel bag for holding extra tools and supplies." + icon_state = "duffel-eng" + item_state = "duffel-eng" + resistance_flags = 0 + +/obj/item/storage/backpack/duffelbag/drone + name = "drone duffel bag" + desc = "A large duffel bag for holding tools and hats." + icon_state = "duffel-drone" + item_state = "duffel-drone" + resistance_flags = FIRE_PROOF + +/obj/item/storage/backpack/duffelbag/drone/PopulateContents() + new /obj/item/screwdriver(src) + new /obj/item/wrench(src) + new /obj/item/weldingtool(src) + new /obj/item/crowbar(src) + new /obj/item/stack/cable_coil/random(src) + new /obj/item/wirecutters(src) + new /obj/item/device/multitool(src) + +/obj/item/storage/backpack/duffelbag/clown + name = "clown's duffel bag" + desc = "A large duffel bag for holding lots of funny gags!" + icon_state = "duffel-clown" + item_state = "duffel-clown" + +/obj/item/storage/backpack/duffelbag/clown/cream_pie/PopulateContents() + for(var/i in 1 to 10) + new /obj/item/reagent_containers/food/snacks/pie/cream(src) + +/obj/item/storage/backpack/duffelbag/syndie + name = "suspicious looking duffel bag" + desc = "A large duffel bag for holding extra tactical supplies." + icon_state = "duffel-syndie" + item_state = "duffel-syndie" + origin_tech = "syndicate=1" + silent = 1 + slowdown = 0 + +/obj/item/storage/backpack/duffelbag/syndie/hitman + desc = "A large duffel bag for holding extra things. There is a Nanotrasen logo on the back." + icon_state = "duffel-syndieammo" + item_state = "duffel-syndieammo" + +/obj/item/storage/backpack/duffelbag/syndie/hitman/PopulateContents() + new /obj/item/clothing/under/lawyer/blacksuit(src) + new /obj/item/clothing/accessory/waistcoat(src) + new /obj/item/clothing/suit/toggle/lawyer/black(src) + new /obj/item/clothing/shoes/laceup(src) + new /obj/item/clothing/gloves/color/black(src) + new /obj/item/clothing/glasses/sunglasses(src) + new /obj/item/clothing/head/fedora(src) + +/obj/item/storage/backpack/duffelbag/syndie/med + name = "medical duffel bag" + desc = "A large duffel bag for holding extra tactical medical supplies." + icon_state = "duffel-syndiemed" + item_state = "duffel-syndiemed" + +/obj/item/storage/backpack/duffelbag/syndie/surgery + name = "surgery duffel bag" + desc = "A suspicious looking duffel bag for holding surgery tools." + icon_state = "duffel-syndiemed" + item_state = "duffel-syndiemed" + +/obj/item/storage/backpack/duffelbag/syndie/surgery/PopulateContents() + new /obj/item/scalpel(src) + new /obj/item/hemostat(src) + new /obj/item/retractor(src) + new /obj/item/circular_saw(src) + new /obj/item/surgicaldrill(src) + new /obj/item/cautery(src) + new /obj/item/surgical_drapes(src) + new /obj/item/clothing/suit/straight_jacket(src) + new /obj/item/clothing/mask/muzzle(src) + new /obj/item/device/mmi/syndie(src) + +/obj/item/storage/backpack/duffelbag/syndie/ammo + name = "ammunition duffel bag" + desc = "A large duffel bag for holding extra weapons ammunition and supplies." + icon_state = "duffel-syndieammo" + item_state = "duffel-syndieammo" + +/obj/item/storage/backpack/duffelbag/syndie/ammo/shotgun + desc = "A large duffel bag, packed to the brim with Bulldog shotgun ammo." + +/obj/item/storage/backpack/duffelbag/syndie/ammo/shotgun/PopulateContents() + for(var/i in 1 to 6) + new /obj/item/ammo_box/magazine/m12g(src) + new /obj/item/ammo_box/magazine/m12g/buckshot(src) + new /obj/item/ammo_box/magazine/m12g/slug(src) + new /obj/item/ammo_box/magazine/m12g/dragon(src) + +/obj/item/storage/backpack/duffelbag/syndie/ammo/smg + desc = "A large duffel bag, packed to the brim with C20r magazines." + +/obj/item/storage/backpack/duffelbag/syndie/ammo/smg/PopulateContents() + for(var/i in 1 to 9) + new /obj/item/ammo_box/magazine/smgm45(src) + +/obj/item/storage/backpack/duffelbag/syndie/c20rbundle + desc = "A large duffel bag containing a C20r, some magazines, and a cheap looking suppressor." + +/obj/item/storage/backpack/duffelbag/syndie/c20rbundle/PopulateContents() + new /obj/item/ammo_box/magazine/smgm45(src) + new /obj/item/ammo_box/magazine/smgm45(src) + new /obj/item/gun/ballistic/automatic/c20r(src) + new /obj/item/suppressor/specialoffer(src) + +/obj/item/storage/backpack/duffelbag/syndie/bulldogbundle + desc = "A large duffel bag containing a Bulldog, several drums, and a collapsed hardsuit." + +/obj/item/storage/backpack/duffelbag/syndie/bulldogbundle/PopulateContents() + new /obj/item/ammo_box/magazine/m12g(src) + new /obj/item/gun/ballistic/automatic/shotgun/bulldog(src) + new /obj/item/ammo_box/magazine/m12g/buckshot(src) + new /obj/item/clothing/glasses/thermal/syndi(src) + +/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle + desc = "A large duffel bag containing a medical equipment, a Donksoft machine gun, a big jumbo box of darts, and a knock-off pair of magboots." + +/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle/PopulateContents() + new /obj/item/clothing/shoes/magboots/syndie(src) + new /obj/item/storage/firstaid/tactical(src) + new /obj/item/gun/ballistic/automatic/l6_saw/toy(src) + new /obj/item/ammo_box/foambox/riot(src) + +/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle + desc = "A large duffel bag containing a medical equipment, a Donksoft machine gun, a big jumbo box of darts, and a knock-off pair of magboots." + +/obj/item/storage/backpack/duffelbag/syndie/med/medicalbundle/PopulateContents() + new /obj/item/clothing/shoes/magboots/syndie(src) + new /obj/item/storage/firstaid/tactical(src) + new /obj/item/gun/ballistic/automatic/l6_saw/toy(src) + new /obj/item/ammo_box/foambox/riot(src) + +/obj/item/storage/backpack/duffelbag/syndie/med/bioterrorbundle + desc = "A large duffel bag containing a deadly chemicals, a chemical spray, chemical grenade, a Donksoft assault rifle, riot grade darts, a minature syringe gun, and a box of syringes" + +/obj/item/storage/backpack/duffelbag/syndie/med/bioterrorbundle/PopulateContents() + new /obj/item/reagent_containers/spray/chemsprayer/bioterror(src) + new /obj/item/storage/box/syndie_kit/chemical(src) + new /obj/item/gun/syringe/syndicate(src) + new /obj/item/gun/ballistic/automatic/c20r/toy(src) + new /obj/item/storage/box/syringes(src) + new /obj/item/ammo_box/foambox/riot(src) + new /obj/item/grenade/chem_grenade/bioterrorfoam(src) + +/obj/item/storage/backpack/duffelbag/syndie/c4/PopulateContents() + for(var/i in 1 to 10) + new /obj/item/grenade/plastic/c4(src) + +/obj/item/storage/backpack/duffelbag/syndie/x4/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/grenade/plastic/x4(src) + +/obj/item/storage/backpack/duffelbag/syndie/firestarter + desc = "A large duffel bag containing New Russian pyro backpack sprayer, a pistol, a pipebomb, fireproof hardsuit, ammo, and other equipment." + +/obj/item/storage/backpack/duffelbag/syndie/firestarter/PopulateContents() + new /obj/item/clothing/under/syndicate/soviet(src) + new /obj/item/watertank/operator(src) + new /obj/item/clothing/suit/space/hardsuit/syndi/elite(src) + new /obj/item/gun/ballistic/automatic/pistol/APS(src) + new /obj/item/ammo_box/magazine/pistolm9mm(src) + new /obj/item/ammo_box/magazine/pistolm9mm(src) + new /obj/item/reagent_containers/food/drinks/bottle/vodka/badminka(src) + new /obj/item/reagent_containers/syringe/stimulants(src) + new /obj/item/grenade/syndieminibomb(src) diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm index 0cae6f9320..883641d43b 100644 --- a/code/game/objects/items/storage/fancy.dm +++ b/code/game/objects/items/storage/fancy.dm @@ -1,273 +1,273 @@ -/* - * The 'fancy' path is for objects like donut boxes that show how many items are in the storage item on the sprite itself - * .. Sorry for the shitty path name, I couldnt think of a better one. - * - * WARNING: var/icon_type is used for both examine text and sprite name. Please look at the procs below and adjust your sprite names accordingly - * TODO: Cigarette boxes should be ported to this standard - * - * Contains: - * Donut Box - * Egg Box - * Candle Box - * Cigarette Box - * Cigar Case - */ - -/obj/item/storage/fancy - icon = 'icons/obj/food/containers.dmi' - icon_state = "donutbox6" - name = "donut box" - resistance_flags = FLAMMABLE - var/icon_type = "donut" - var/spawn_type = null - var/fancy_open = FALSE - -/obj/item/storage/fancy/PopulateContents() - for(var/i = 1 to storage_slots) - new spawn_type(src) - -/obj/item/storage/fancy/update_icon(itemremoved = 0) - if(fancy_open) - var/total_contents = src.contents.len - itemremoved - icon_state = "[icon_type]box[total_contents]" - else - icon_state = "[icon_type]box" - -/obj/item/storage/fancy/examine(mob/user) - ..() - if(fancy_open) - if(contents.len == 1) - to_chat(user, "There is one [src.icon_type] left.") - else - to_chat(user, "There are [contents.len <= 0 ? "no" : "[src.contents.len]"] [src.icon_type]s left.") - -/obj/item/storage/fancy/attack_self(mob/user) - fancy_open = !fancy_open - update_icon() - -/obj/item/storage/fancy/content_can_dump(atom/dest_object, mob/user) - . = ..() - if(.) - fancy_open = TRUE - update_icon() - -/obj/item/storage/fancy/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) - fancy_open = TRUE - return ..() - -/obj/item/storage/fancy/remove_from_storage(obj/item/W, atom/new_location, burn = 0) - fancy_open = TRUE - return ..() - -/* - * Donut Box - */ - -/obj/item/storage/fancy/donut_box - icon = 'icons/obj/food/containers.dmi' - icon_state = "donutbox6" - icon_type = "donut" - name = "donut box" - storage_slots = 6 - can_hold = list(/obj/item/reagent_containers/food/snacks/donut) - spawn_type = /obj/item/reagent_containers/food/snacks/donut - fancy_open = TRUE - -/* - * Egg Box - */ - -/obj/item/storage/fancy/egg_box - icon = 'icons/obj/food/containers.dmi' - icon_state = "eggbox" - icon_type = "egg" - lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi' - righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi' - name = "egg box" - storage_slots = 12 - can_hold = list(/obj/item/reagent_containers/food/snacks/egg) - spawn_type = /obj/item/reagent_containers/food/snacks/egg - -/* - * Candle Box - */ - -/obj/item/storage/fancy/candle_box - name = "candle pack" - desc = "A pack of red candles." - icon = 'icons/obj/candle.dmi' - icon_state = "candlebox5" - icon_type = "candle" - item_state = "candlebox5" - storage_slots = 5 - throwforce = 2 - slot_flags = SLOT_BELT - spawn_type = /obj/item/candle - fancy_open = TRUE - -/obj/item/storage/fancy/candle_box/attack_self(mob_user) - return - -//////////// -//CIG PACK// -//////////// -/obj/item/storage/fancy/cigarettes - name = "\improper Space Cigarettes packet" - desc = "The most popular brand of cigarettes, sponsors of the Space Olympics." - icon = 'icons/obj/cigarettes.dmi' - icon_state = "cig" - item_state = "cigpacket" - w_class = WEIGHT_CLASS_TINY - throwforce = 0 - slot_flags = SLOT_BELT - storage_slots = 6 - can_hold = list(/obj/item/clothing/mask/cigarette, /obj/item/lighter) - icon_type = "cigarette" - spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette - -/obj/item/storage/fancy/cigarettes/AltClick(mob/user) - if(user.get_active_held_item()) - return - for(var/obj/item/lighter/lighter in src) - remove_from_storage(lighter, user.loc) - user.put_in_active_hand(lighter) - break - -/obj/item/storage/fancy/cigarettes/update_icon() - if(fancy_open || !contents.len) - cut_overlays() - if(!contents.len) - icon_state = "[initial(icon_state)]_empty" - else - icon_state = initial(icon_state) - add_overlay("[icon_state]_open") - var/i = contents.len - for(var/C in contents) - var/mutable_appearance/inserted_overlay = mutable_appearance(icon) - inserted_overlay.pixel_x = 1 * (i - 1) - if(istype(C, /obj/item/lighter/greyscale)) - inserted_overlay.icon_state = "lighter_in" - else if(istype(C, /obj/item/lighter)) - inserted_overlay.icon_state = "zippo_in" - else - inserted_overlay.icon_state = "cigarette" - add_overlay(inserted_overlay) - i-- - else - cut_overlays() - -/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) - if(!ismob(M)) - return - var/obj/item/clothing/mask/cigarette/cig = locate(/obj/item/clothing/mask/cigarette) in contents - if(cig) - if(M == user && contents.len > 0 && !user.wear_mask) - var/obj/item/clothing/mask/cigarette/W = cig - remove_from_storage(W, M) - M.equip_to_slot_if_possible(W, slot_wear_mask) - contents -= W - to_chat(user, "You take a [icon_type] out of the pack.") - else - ..() - else - to_chat(user, "There are no [icon_type]s left in the pack.") - -/obj/item/storage/fancy/cigarettes/dromedaryco - name = "\improper DromedaryCo packet" - desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"" - icon_state = "dromedary" - spawn_type = /obj/item/clothing/mask/cigarette/dromedary - -/obj/item/storage/fancy/cigarettes/cigpack_uplift - name = "\improper Uplift Smooth packet" - desc = "Your favorite brand, now menthol flavored." - icon_state = "uplift" - spawn_type = /obj/item/clothing/mask/cigarette/uplift - -/obj/item/storage/fancy/cigarettes/cigpack_robust - name = "\improper Robust packet" - desc = "Smoked by the robust." - icon_state = "robust" - spawn_type = /obj/item/clothing/mask/cigarette/robust - -/obj/item/storage/fancy/cigarettes/cigpack_robustgold - name = "\improper Robust Gold packet" - desc = "Smoked by the truly robust." - icon_state = "robustg" - spawn_type = /obj/item/clothing/mask/cigarette/robustgold - -/obj/item/storage/fancy/cigarettes/cigpack_carp - name = "\improper Carp Classic packet" - desc = "Since 2313." - icon_state = "carp" - spawn_type = /obj/item/clothing/mask/cigarette/carp - -/obj/item/storage/fancy/cigarettes/cigpack_syndicate - name = "cigarette packet" - desc = "An obscure brand of cigarettes." - icon_state = "syndie" - spawn_type = /obj/item/clothing/mask/cigarette/syndicate - -/obj/item/storage/fancy/cigarettes/cigpack_midori - name = "\improper Midori Tabako packet" - desc = "You can't understand the runes, but the packet smells funny." - icon_state = "midori" - spawn_type = /obj/item/clothing/mask/cigarette/rollie - -/obj/item/storage/fancy/cigarettes/cigpack_shadyjims - name = "\improper Shady Jim's Super Slims packet" - desc = "Is your weight slowing you down? Having trouble running away from gravitational singularities? Can't stop stuffing your mouth? Smoke Shady Jim's Super Slims and watch all that fat burn away. Guaranteed results!" - icon_state = "shadyjim" - spawn_type = /obj/item/clothing/mask/cigarette/shadyjims - -/obj/item/storage/fancy/rollingpapers - name = "rolling paper pack" - desc = "A pack of NanoTrasen brand rolling papers." - w_class = WEIGHT_CLASS_TINY - icon = 'icons/obj/cigarettes.dmi' - icon_state = "cig_paper_pack" - storage_slots = 10 - icon_type = "rolling paper" - can_hold = list(/obj/item/rollingpaper) - spawn_type = /obj/item/rollingpaper - -/obj/item/storage/fancy/rollingpapers/update_icon() - cut_overlays() - if(!contents.len) - add_overlay("[icon_state]_empty") - -///////////// -//CIGAR BOX// -///////////// - -/obj/item/storage/fancy/cigarettes/cigars - name = "\improper premium cigar case" - desc = "A case of premium cigars. Very expensive." - icon = 'icons/obj/cigarettes.dmi' - icon_state = "cigarcase" - w_class = WEIGHT_CLASS_NORMAL - storage_slots = 5 - can_hold = list(/obj/item/clothing/mask/cigarette/cigar) - icon_type = "premium cigar" - spawn_type = /obj/item/clothing/mask/cigarette/cigar - -/obj/item/storage/fancy/cigarettes/cigars/update_icon() - cut_overlays() - if(fancy_open) - add_overlay("[icon_state]_open") - var/mutable_appearance/cigar_overlay = mutable_appearance(icon, icon_type) - for(var/c = contents.len, c >= 1, c--) - cigar_overlay.pixel_x = 4 * (c - 1) - add_overlay(cigar_overlay) - else - icon_state = "cigarcase" - -/obj/item/storage/fancy/cigarettes/cigars/cohiba - name = "\improper cohiba robusto cigar case" - desc = "A case of imported Cohiba cigars, renowned for their strong flavor." - spawn_type = /obj/item/clothing/mask/cigarette/cigar/cohiba - -/obj/item/storage/fancy/cigarettes/cigars/havana - name = "\improper premium havanian cigar case" - desc = "A case of classy Havanian cigars." - spawn_type = /obj/item/clothing/mask/cigarette/cigar/havana +/* + * The 'fancy' path is for objects like donut boxes that show how many items are in the storage item on the sprite itself + * .. Sorry for the shitty path name, I couldnt think of a better one. + * + * WARNING: var/icon_type is used for both examine text and sprite name. Please look at the procs below and adjust your sprite names accordingly + * TODO: Cigarette boxes should be ported to this standard + * + * Contains: + * Donut Box + * Egg Box + * Candle Box + * Cigarette Box + * Cigar Case + */ + +/obj/item/storage/fancy + icon = 'icons/obj/food/containers.dmi' + icon_state = "donutbox6" + name = "donut box" + resistance_flags = FLAMMABLE + var/icon_type = "donut" + var/spawn_type = null + var/fancy_open = FALSE + +/obj/item/storage/fancy/PopulateContents() + for(var/i = 1 to storage_slots) + new spawn_type(src) + +/obj/item/storage/fancy/update_icon(itemremoved = 0) + if(fancy_open) + var/total_contents = src.contents.len - itemremoved + icon_state = "[icon_type]box[total_contents]" + else + icon_state = "[icon_type]box" + +/obj/item/storage/fancy/examine(mob/user) + ..() + if(fancy_open) + if(contents.len == 1) + to_chat(user, "There is one [src.icon_type] left.") + else + to_chat(user, "There are [contents.len <= 0 ? "no" : "[src.contents.len]"] [src.icon_type]s left.") + +/obj/item/storage/fancy/attack_self(mob/user) + fancy_open = !fancy_open + update_icon() + +/obj/item/storage/fancy/dump_content_at(atom/dest_object, mob/user) + . = ..() + if(.) + fancy_open = TRUE + update_icon() + +/obj/item/storage/fancy/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) + fancy_open = TRUE + return ..() + +/obj/item/storage/fancy/remove_from_storage(obj/item/W, atom/new_location, burn = 0) + fancy_open = TRUE + return ..() + +/* + * Donut Box + */ + +/obj/item/storage/fancy/donut_box + icon = 'icons/obj/food/containers.dmi' + icon_state = "donutbox6" + icon_type = "donut" + name = "donut box" + storage_slots = 6 + can_hold = list(/obj/item/reagent_containers/food/snacks/donut) + spawn_type = /obj/item/reagent_containers/food/snacks/donut + fancy_open = TRUE + +/* + * Egg Box + */ + +/obj/item/storage/fancy/egg_box + icon = 'icons/obj/food/containers.dmi' + icon_state = "eggbox" + icon_type = "egg" + lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi' + righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi' + name = "egg box" + storage_slots = 12 + can_hold = list(/obj/item/reagent_containers/food/snacks/egg) + spawn_type = /obj/item/reagent_containers/food/snacks/egg + +/* + * Candle Box + */ + +/obj/item/storage/fancy/candle_box + name = "candle pack" + desc = "A pack of red candles." + icon = 'icons/obj/candle.dmi' + icon_state = "candlebox5" + icon_type = "candle" + item_state = "candlebox5" + storage_slots = 5 + throwforce = 2 + slot_flags = SLOT_BELT + spawn_type = /obj/item/candle + fancy_open = TRUE + +/obj/item/storage/fancy/candle_box/attack_self(mob_user) + return + +//////////// +//CIG PACK// +//////////// +/obj/item/storage/fancy/cigarettes + name = "\improper Space Cigarettes packet" + desc = "The most popular brand of cigarettes, sponsors of the Space Olympics." + icon = 'icons/obj/cigarettes.dmi' + icon_state = "cig" + item_state = "cigpacket" + w_class = WEIGHT_CLASS_TINY + throwforce = 0 + slot_flags = SLOT_BELT + storage_slots = 6 + can_hold = list(/obj/item/clothing/mask/cigarette, /obj/item/lighter) + icon_type = "cigarette" + spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette + +/obj/item/storage/fancy/cigarettes/AltClick(mob/user) + if(user.get_active_held_item()) + return + for(var/obj/item/lighter/lighter in src) + remove_from_storage(lighter, user.loc) + user.put_in_active_hand(lighter) + break + +/obj/item/storage/fancy/cigarettes/update_icon() + if(fancy_open || !contents.len) + cut_overlays() + if(!contents.len) + icon_state = "[initial(icon_state)]_empty" + else + icon_state = initial(icon_state) + add_overlay("[icon_state]_open") + var/i = contents.len + for(var/C in contents) + var/mutable_appearance/inserted_overlay = mutable_appearance(icon) + inserted_overlay.pixel_x = 1 * (i - 1) + if(istype(C, /obj/item/lighter/greyscale)) + inserted_overlay.icon_state = "lighter_in" + else if(istype(C, /obj/item/lighter)) + inserted_overlay.icon_state = "zippo_in" + else + inserted_overlay.icon_state = "cigarette" + add_overlay(inserted_overlay) + i-- + else + cut_overlays() + +/obj/item/storage/fancy/cigarettes/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob) + if(!ismob(M)) + return + var/obj/item/clothing/mask/cigarette/cig = locate(/obj/item/clothing/mask/cigarette) in contents + if(cig) + if(M == user && contents.len > 0 && !user.wear_mask) + var/obj/item/clothing/mask/cigarette/W = cig + remove_from_storage(W, M) + M.equip_to_slot_if_possible(W, slot_wear_mask) + contents -= W + to_chat(user, "You take a [icon_type] out of the pack.") + else + ..() + else + to_chat(user, "There are no [icon_type]s left in the pack.") + +/obj/item/storage/fancy/cigarettes/dromedaryco + name = "\improper DromedaryCo packet" + desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\"" + icon_state = "dromedary" + spawn_type = /obj/item/clothing/mask/cigarette/dromedary + +/obj/item/storage/fancy/cigarettes/cigpack_uplift + name = "\improper Uplift Smooth packet" + desc = "Your favorite brand, now menthol flavored." + icon_state = "uplift" + spawn_type = /obj/item/clothing/mask/cigarette/uplift + +/obj/item/storage/fancy/cigarettes/cigpack_robust + name = "\improper Robust packet" + desc = "Smoked by the robust." + icon_state = "robust" + spawn_type = /obj/item/clothing/mask/cigarette/robust + +/obj/item/storage/fancy/cigarettes/cigpack_robustgold + name = "\improper Robust Gold packet" + desc = "Smoked by the truly robust." + icon_state = "robustg" + spawn_type = /obj/item/clothing/mask/cigarette/robustgold + +/obj/item/storage/fancy/cigarettes/cigpack_carp + name = "\improper Carp Classic packet" + desc = "Since 2313." + icon_state = "carp" + spawn_type = /obj/item/clothing/mask/cigarette/carp + +/obj/item/storage/fancy/cigarettes/cigpack_syndicate + name = "cigarette packet" + desc = "An obscure brand of cigarettes." + icon_state = "syndie" + spawn_type = /obj/item/clothing/mask/cigarette/syndicate + +/obj/item/storage/fancy/cigarettes/cigpack_midori + name = "\improper Midori Tabako packet" + desc = "You can't understand the runes, but the packet smells funny." + icon_state = "midori" + spawn_type = /obj/item/clothing/mask/cigarette/rollie + +/obj/item/storage/fancy/cigarettes/cigpack_shadyjims + name = "\improper Shady Jim's Super Slims packet" + desc = "Is your weight slowing you down? Having trouble running away from gravitational singularities? Can't stop stuffing your mouth? Smoke Shady Jim's Super Slims and watch all that fat burn away. Guaranteed results!" + icon_state = "shadyjim" + spawn_type = /obj/item/clothing/mask/cigarette/shadyjims + +/obj/item/storage/fancy/rollingpapers + name = "rolling paper pack" + desc = "A pack of Nanotrasen brand rolling papers." + w_class = WEIGHT_CLASS_TINY + icon = 'icons/obj/cigarettes.dmi' + icon_state = "cig_paper_pack" + storage_slots = 10 + icon_type = "rolling paper" + can_hold = list(/obj/item/rollingpaper) + spawn_type = /obj/item/rollingpaper + +/obj/item/storage/fancy/rollingpapers/update_icon() + cut_overlays() + if(!contents.len) + add_overlay("[icon_state]_empty") + +///////////// +//CIGAR BOX// +///////////// + +/obj/item/storage/fancy/cigarettes/cigars + name = "\improper premium cigar case" + desc = "A case of premium cigars. Very expensive." + icon = 'icons/obj/cigarettes.dmi' + icon_state = "cigarcase" + w_class = WEIGHT_CLASS_NORMAL + storage_slots = 5 + can_hold = list(/obj/item/clothing/mask/cigarette/cigar) + icon_type = "premium cigar" + spawn_type = /obj/item/clothing/mask/cigarette/cigar + +/obj/item/storage/fancy/cigarettes/cigars/update_icon() + cut_overlays() + if(fancy_open) + add_overlay("[icon_state]_open") + var/mutable_appearance/cigar_overlay = mutable_appearance(icon, icon_type) + for(var/c = contents.len, c >= 1, c--) + cigar_overlay.pixel_x = 4 * (c - 1) + add_overlay(cigar_overlay) + else + icon_state = "cigarcase" + +/obj/item/storage/fancy/cigarettes/cigars/cohiba + name = "\improper cohiba robusto cigar case" + desc = "A case of imported Cohiba cigars, renowned for their strong flavor." + spawn_type = /obj/item/clothing/mask/cigarette/cigar/cohiba + +/obj/item/storage/fancy/cigarettes/cigars/havana + name = "\improper premium havanian cigar case" + desc = "A case of classy Havanian cigars." + spawn_type = /obj/item/clothing/mask/cigarette/cigar/havana diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm index c2d73ebc13..346e9ba409 100644 --- a/code/game/objects/items/storage/lockbox.dm +++ b/code/game/objects/items/storage/lockbox.dm @@ -1,182 +1,182 @@ -/obj/item/storage/lockbox - name = "lockbox" - desc = "A locked box." - icon_state = "lockbox+l" - item_state = "syringe_kit" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - w_class = WEIGHT_CLASS_BULKY - max_w_class = WEIGHT_CLASS_NORMAL - max_combined_w_class = 14 //The sum of the w_classes of all the items in this storage item. - storage_slots = 4 - req_access = list(ACCESS_ARMORY) - var/locked = TRUE - var/broken = FALSE - var/open = FALSE - var/icon_locked = "lockbox+l" - var/icon_closed = "lockbox" - var/icon_broken = "lockbox+b" - - -/obj/item/storage/lockbox/attackby(obj/item/W, mob/user, params) - if(W.GetID()) - if(broken) - to_chat(user, "It appears to be broken.") - return - if(allowed(user)) - locked = !locked - if(locked) - icon_state = icon_locked - to_chat(user, "You lock the [src.name]!") - close_all() - return - else - icon_state = icon_closed - to_chat(user, "You unlock the [src.name]!") - return - else - to_chat(user, "Access Denied.") - return - if(!locked) - return ..() - else - to_chat(user, "It's locked!") - -/obj/item/storage/lockbox/MouseDrop(over_object, src_location, over_location) - if (locked) - src.add_fingerprint(usr) - to_chat(usr, "It's locked!") - return 0 - ..() - -/obj/item/storage/lockbox/emag_act(mob/user) - if(!broken) - broken = TRUE - locked = FALSE - desc += "It appears to be broken." - icon_state = src.icon_broken - if(user) - visible_message("\The [src] has been broken by [user] with an electromagnetic card!") - return - -/obj/item/storage/lockbox/show_to(mob/user) - if(locked) - to_chat(user, "It's locked!") - else - ..() - return - -//Check the destination item type for contentto. -/obj/item/storage/lockbox/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - if(locked) - to_chat(user, "It's locked!") - return 0 - open = TRUE - return ..() - -/obj/item/storage/lockbox/can_be_inserted(obj/item/W, stop_messages = 0) - if(locked) - return 0 - return ..() - -/obj/item/storage/lockbox/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) - open = TRUE - update_icon() - return ..() -/obj/item/storage/lockbox/remove_from_storage(obj/item/W, atom/new_location, burn = 0) - open = TRUE - update_icon() - return ..() - -/obj/item/storage/lockbox/loyalty - name = "lockbox of mindshield implants" - req_access = list(ACCESS_SECURITY) - -/obj/item/storage/lockbox/loyalty/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/implantcase/mindshield(src) - new /obj/item/implanter/mindshield(src) - - -/obj/item/storage/lockbox/clusterbang - name = "lockbox of clusterbangs" - desc = "You have a bad feeling about opening this." - req_access = list(ACCESS_SECURITY) - -/obj/item/storage/lockbox/clusterbang/PopulateContents() - new /obj/item/grenade/clusterbuster(src) - -/obj/item/storage/lockbox/medal - name = "medal box" - desc = "A locked box used to store medals of honor." - icon_state = "medalbox+l" - item_state = "syringe_kit" - lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' - w_class = WEIGHT_CLASS_NORMAL - max_w_class = WEIGHT_CLASS_SMALL - storage_slots = 10 - max_combined_w_class = 20 - req_access = list(ACCESS_CAPTAIN) - icon_locked = "medalbox+l" - icon_closed = "medalbox" - icon_broken = "medalbox+b" - can_hold = list(/obj/item/clothing/accessory/medal) - -/obj/item/storage/lockbox/medal/AltClick() - if(!locked) - open = (open ? FALSE : TRUE) - update_icon() - ..() - -/obj/item/storage/lockbox/medal/PopulateContents() - new /obj/item/clothing/accessory/medal/gold/captain(src) - new /obj/item/clothing/accessory/medal/silver/valor(src) - new /obj/item/clothing/accessory/medal/silver/valor(src) - new /obj/item/clothing/accessory/medal/silver/security(src) - new /obj/item/clothing/accessory/medal/bronze_heart(src) - new /obj/item/clothing/accessory/medal/plasma/nobel_science(src) - new /obj/item/clothing/accessory/medal/plasma/nobel_science(src) - for(var/i in 1 to 3) - new /obj/item/clothing/accessory/medal/conduct(src) - -/obj/item/storage/lockbox/medal/update_icon() - cut_overlays() - if(locked) - icon_state = "medalbox+l" - open = FALSE - else - icon_state = "medalbox" - if(open) - icon_state += "open" - if(broken) - icon_state += "+b" - if(contents && open) - for (var/i in 1 to contents.len) - var/obj/item/clothing/accessory/medal/M = contents[i] - var/mutable_appearance/medalicon = mutable_appearance(initial(icon), M.medaltype) - if(i > 1 && i <= 5) - medalicon.pixel_x += ((i-1)*3) - else if(i > 5) - medalicon.pixel_y -= 7 - medalicon.pixel_x -= 2 - medalicon.pixel_x += ((i-6)*3) - add_overlay(medalicon) - -/obj/item/storage/lockbox/medal/sec - name = "security medal box" - desc = "A locked box used to store medals to be given to members of the security department." - req_access = list(ACCESS_HOS) - -/obj/item/storage/lockbox/medal/sec/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/clothing/accessory/medal/silver/security(src) - -/obj/item/storage/lockbox/medal/sci - name = "science medal box" - desc = "A locked box used to store medals to be given to members of the science department." - req_access = list(ACCESS_RD) - -/obj/item/storage/lockbox/medal/sci/PopulateContents() - for(var/i in 1 to 3) +/obj/item/storage/lockbox + name = "lockbox" + desc = "A locked box." + icon_state = "lockbox+l" + item_state = "syringe_kit" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + w_class = WEIGHT_CLASS_BULKY + max_w_class = WEIGHT_CLASS_NORMAL + max_combined_w_class = 14 //The sum of the w_classes of all the items in this storage item. + storage_slots = 4 + req_access = list(ACCESS_ARMORY) + var/locked = TRUE + var/broken = FALSE + var/open = FALSE + var/icon_locked = "lockbox+l" + var/icon_closed = "lockbox" + var/icon_broken = "lockbox+b" + + +/obj/item/storage/lockbox/attackby(obj/item/W, mob/user, params) + if(W.GetID()) + if(broken) + to_chat(user, "It appears to be broken.") + return + if(allowed(user)) + locked = !locked + if(locked) + icon_state = icon_locked + to_chat(user, "You lock the [src.name]!") + close_all() + return + else + icon_state = icon_closed + to_chat(user, "You unlock the [src.name]!") + return + else + to_chat(user, "Access Denied.") + return + if(!locked) + return ..() + else + to_chat(user, "It's locked!") + +/obj/item/storage/lockbox/MouseDrop(over_object, src_location, over_location) + if (locked) + src.add_fingerprint(usr) + to_chat(usr, "It's locked!") + return 0 + ..() + +/obj/item/storage/lockbox/emag_act(mob/user) + if(!broken) + broken = TRUE + locked = FALSE + desc += "It appears to be broken." + icon_state = src.icon_broken + if(user) + visible_message("\The [src] has been broken by [user] with an electromagnetic card!") + return + +/obj/item/storage/lockbox/show_to(mob/user) + if(locked) + to_chat(user, "It's locked!") + else + ..() + return + +//Check the destination item type for contentto. +/obj/item/storage/lockbox/storage_contents_dump_act(obj/item/storage/src_object, mob/user) + if(locked) + to_chat(user, "It's locked!") + return null + open = TRUE + return ..() + +/obj/item/storage/lockbox/can_be_inserted(obj/item/W, stop_messages = 0) + if(locked) + return 0 + return ..() + +/obj/item/storage/lockbox/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) + open = TRUE + update_icon() + return ..() +/obj/item/storage/lockbox/remove_from_storage(obj/item/W, atom/new_location, burn = 0) + open = TRUE + update_icon() + return ..() + +/obj/item/storage/lockbox/loyalty + name = "lockbox of mindshield implants" + req_access = list(ACCESS_SECURITY) + +/obj/item/storage/lockbox/loyalty/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/implantcase/mindshield(src) + new /obj/item/implanter/mindshield(src) + + +/obj/item/storage/lockbox/clusterbang + name = "lockbox of clusterbangs" + desc = "You have a bad feeling about opening this." + req_access = list(ACCESS_SECURITY) + +/obj/item/storage/lockbox/clusterbang/PopulateContents() + new /obj/item/grenade/clusterbuster(src) + +/obj/item/storage/lockbox/medal + name = "medal box" + desc = "A locked box used to store medals of honor." + icon_state = "medalbox+l" + item_state = "syringe_kit" + lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' + w_class = WEIGHT_CLASS_NORMAL + max_w_class = WEIGHT_CLASS_SMALL + storage_slots = 10 + max_combined_w_class = 20 + req_access = list(ACCESS_CAPTAIN) + icon_locked = "medalbox+l" + icon_closed = "medalbox" + icon_broken = "medalbox+b" + can_hold = list(/obj/item/clothing/accessory/medal) + +/obj/item/storage/lockbox/medal/AltClick() + if(!locked) + open = (open ? FALSE : TRUE) + update_icon() + ..() + +/obj/item/storage/lockbox/medal/PopulateContents() + new /obj/item/clothing/accessory/medal/gold/captain(src) + new /obj/item/clothing/accessory/medal/silver/valor(src) + new /obj/item/clothing/accessory/medal/silver/valor(src) + new /obj/item/clothing/accessory/medal/silver/security(src) + new /obj/item/clothing/accessory/medal/bronze_heart(src) + new /obj/item/clothing/accessory/medal/plasma/nobel_science(src) + new /obj/item/clothing/accessory/medal/plasma/nobel_science(src) + for(var/i in 1 to 3) + new /obj/item/clothing/accessory/medal/conduct(src) + +/obj/item/storage/lockbox/medal/update_icon() + cut_overlays() + if(locked) + icon_state = "medalbox+l" + open = FALSE + else + icon_state = "medalbox" + if(open) + icon_state += "open" + if(broken) + icon_state += "+b" + if(contents && open) + for (var/i in 1 to contents.len) + var/obj/item/clothing/accessory/medal/M = contents[i] + var/mutable_appearance/medalicon = mutable_appearance(initial(icon), M.medaltype) + if(i > 1 && i <= 5) + medalicon.pixel_x += ((i-1)*3) + else if(i > 5) + medalicon.pixel_y -= 7 + medalicon.pixel_x -= 2 + medalicon.pixel_x += ((i-6)*3) + add_overlay(medalicon) + +/obj/item/storage/lockbox/medal/sec + name = "security medal box" + desc = "A locked box used to store medals to be given to members of the security department." + req_access = list(ACCESS_HOS) + +/obj/item/storage/lockbox/medal/sec/PopulateContents() + for(var/i in 1 to 3) + new /obj/item/clothing/accessory/medal/silver/security(src) + +/obj/item/storage/lockbox/medal/sci + name = "science medal box" + desc = "A locked box used to store medals to be given to members of the science department." + req_access = list(ACCESS_RD) + +/obj/item/storage/lockbox/medal/sci/PopulateContents() + for(var/i in 1 to 3) new /obj/item/clothing/accessory/medal/plasma/nobel_science(src) \ No newline at end of file diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index c9bbfdd308..6620ec5265 100644 --- a/code/game/objects/items/storage/secure.dm +++ b/code/game/objects/items/storage/secure.dm @@ -1,197 +1,197 @@ -/* - * Absorbs /obj/item/secstorage. - * Reimplements it only slightly to use existing storage functionality. - * - * Contains: - * Secure Briefcase - * Wall Safe - */ - -// ----------------------------- -// Generic Item -// ----------------------------- -/obj/item/storage/secure - name = "secstorage" - var/icon_locking = "secureb" - var/icon_sparking = "securespark" - var/icon_opened = "secure0" - var/locked = TRUE - var/code = "" - var/l_code = null - var/l_set = 0 - var/l_setshort = 0 - var/l_hacking = 0 - var/open = FALSE - w_class = WEIGHT_CLASS_NORMAL - max_w_class = WEIGHT_CLASS_SMALL - max_combined_w_class = 14 - -/obj/item/storage/secure/examine(mob/user) - ..() - to_chat(user, text("The service panel is [src.open ? "open" : "closed"].")) - -/obj/item/storage/secure/attackby(obj/item/W, mob/user, params) - if(locked) - if (istype(W, /obj/item/screwdriver)) - if (do_after(user, 20*W.toolspeed, target = src)) - src.open =! src.open - user.show_message("You [open ? "open" : "close"] the service panel.", 1) - return - if ((istype(W, /obj/item/device/multitool)) && (src.open == 1)&& (!src.l_hacking)) - user.show_message("Now attempting to reset internal memory, please hold.", 1) - src.l_hacking = 1 - if (do_after(usr, 100*W.toolspeed, target = src)) - if (prob(33)) - src.l_setshort = 1 - src.l_set = 0 - user.show_message("Internal memory reset. Please give it a few seconds to reinitialize.", 1) - sleep(80) - src.l_setshort = 0 - src.l_hacking = 0 - else - user.show_message("Unable to reset internal memory.", 1) - src.l_hacking = 0 - else - src.l_hacking = 0 - return - //At this point you have exhausted all the special things to do when locked - // ... but it's still locked. - return - - // -> storage/attackby() what with handle insertion, etc - return ..() - -/obj/item/storage/secure/MouseDrop(over_object, src_location, over_location) - if (locked) - src.add_fingerprint(usr) - to_chat(usr, "It's locked!") - return 0 - ..() - -/obj/item/storage/secure/attack_self(mob/user) - user.set_machine(src) - var/dat = text("[]
\n\nLock Status: []",src, (src.locked ? "LOCKED" : "UNLOCKED")) - var/message = "Code" - if ((src.l_set == 0) && (!src.l_setshort)) - dat += text("

\n5-DIGIT PASSCODE NOT SET.
ENTER NEW PASSCODE.
") - if (src.l_setshort) - dat += text("

\nALERT: MEMORY SYSTEM ERROR - 6040 201") - message = text("[]", src.code) - if (!src.locked) - message = "*****" - dat += text("


\n>[]
\n1-2-3
\n4-5-6
\n7-8-9
\nR-0-E
\n
", message, src, src, src, src, src, src, src, src, src, src, src, src) - user << browse(dat, "window=caselock;size=300x280") - -/obj/item/storage/secure/Topic(href, href_list) - ..() - if ((usr.stat || usr.restrained()) || (get_dist(src, usr) > 1)) - return - if (href_list["type"]) - if (href_list["type"] == "E") - if ((src.l_set == 0) && (length(src.code) == 5) && (!src.l_setshort) && (src.code != "ERROR")) - src.l_code = src.code - src.l_set = 1 - else if ((src.code == src.l_code) && (src.l_set == 1)) - src.locked = FALSE - cut_overlays() - add_overlay(icon_opened) - src.code = null - else - src.code = "ERROR" - else - if ((href_list["type"] == "R") && (!src.l_setshort)) - src.locked = TRUE - cut_overlays() - src.code = null - src.close(usr) - else - src.code += text("[]", sanitize_text(href_list["type"])) - if (length(src.code) > 5) - src.code = "ERROR" - src.add_fingerprint(usr) - for(var/mob/M in viewers(1, src.loc)) - if ((M.client && M.machine == src)) - src.attack_self(M) - return - return - -/obj/item/storage/secure/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - if(locked) - to_chat(user, "It's locked!") - return 0 - return ..() - -/obj/item/storage/secure/can_be_inserted(obj/item/W, stop_messages = 0) - if(locked) - return 0 - return ..() - - -// ----------------------------- -// Secure Briefcase -// ----------------------------- -/obj/item/storage/secure/briefcase - name = "secure briefcase" - icon = 'icons/obj/storage.dmi' - icon_state = "secure" - item_state = "sec-case" - lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi' - righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi' - desc = "A large briefcase with a digital locking system." - force = 8 - hitsound = "swing_hit" - throw_speed = 2 - throw_range = 4 - w_class = WEIGHT_CLASS_BULKY - max_w_class = WEIGHT_CLASS_NORMAL - max_combined_w_class = 21 - attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked") - -/obj/item/storage/secure/briefcase/PopulateContents() - new /obj/item/paper(src) - new /obj/item/pen(src) - -/obj/item/storage/secure/briefcase/attack_hand(mob/user) - if ((src.loc == user) && (src.locked == 1)) - to_chat(usr, "[src] is locked and cannot be opened!") - add_fingerprint(user) - else - ..() - -//Syndie variant of Secure Briefcase. Contains space cash, slightly more robust. -/obj/item/storage/secure/briefcase/syndie - force = 15 - -/obj/item/storage/secure/briefcase/syndie/PopulateContents() - ..() - for(var/i = 0, i < storage_slots - 2, i++) - new /obj/item/stack/spacecash/c1000(src) - - -// ----------------------------- -// Secure Safe -// ----------------------------- - -/obj/item/storage/secure/safe - name = "secure safe" - icon = 'icons/obj/storage.dmi' - icon_state = "safe" - icon_opened = "safe0" - icon_locking = "safeb" - icon_sparking = "safespark" - force = 8 - w_class = WEIGHT_CLASS_GIGANTIC - max_w_class = 8 - anchored = TRUE - density = FALSE - cant_hold = list(/obj/item/storage/secure/briefcase) - -/obj/item/storage/secure/safe/PopulateContents() - new /obj/item/paper(src) - new /obj/item/pen(src) - -/obj/item/storage/secure/safe/attack_hand(mob/user) - return attack_self(user) - -/obj/item/storage/secure/safe/HoS - name = "head of security's safe" +/* + * Absorbs /obj/item/secstorage. + * Reimplements it only slightly to use existing storage functionality. + * + * Contains: + * Secure Briefcase + * Wall Safe + */ + +// ----------------------------- +// Generic Item +// ----------------------------- +/obj/item/storage/secure + name = "secstorage" + var/icon_locking = "secureb" + var/icon_sparking = "securespark" + var/icon_opened = "secure0" + var/locked = TRUE + var/code = "" + var/l_code = null + var/l_set = 0 + var/l_setshort = 0 + var/l_hacking = 0 + var/open = FALSE + w_class = WEIGHT_CLASS_NORMAL + max_w_class = WEIGHT_CLASS_SMALL + max_combined_w_class = 14 + +/obj/item/storage/secure/examine(mob/user) + ..() + to_chat(user, text("The service panel is [src.open ? "open" : "closed"].")) + +/obj/item/storage/secure/attackby(obj/item/W, mob/user, params) + if(locked) + if (istype(W, /obj/item/screwdriver)) + if (do_after(user, 20*W.toolspeed, target = src)) + src.open =! src.open + user.show_message("You [open ? "open" : "close"] the service panel.", 1) + return + if ((istype(W, /obj/item/device/multitool)) && (src.open == 1)&& (!src.l_hacking)) + user.show_message("Now attempting to reset internal memory, please hold.", 1) + src.l_hacking = 1 + if (do_after(usr, 100*W.toolspeed, target = src)) + if (prob(33)) + src.l_setshort = 1 + src.l_set = 0 + user.show_message("Internal memory reset. Please give it a few seconds to reinitialize.", 1) + sleep(80) + src.l_setshort = 0 + src.l_hacking = 0 + else + user.show_message("Unable to reset internal memory.", 1) + src.l_hacking = 0 + else + src.l_hacking = 0 + return + //At this point you have exhausted all the special things to do when locked + // ... but it's still locked. + return + + // -> storage/attackby() what with handle insertion, etc + return ..() + +/obj/item/storage/secure/MouseDrop(over_object, src_location, over_location) + if (locked) + src.add_fingerprint(usr) + to_chat(usr, "It's locked!") + return 0 + ..() + +/obj/item/storage/secure/attack_self(mob/user) + user.set_machine(src) + var/dat = text("[]
\n\nLock Status: []",src, (src.locked ? "LOCKED" : "UNLOCKED")) + var/message = "Code" + if ((src.l_set == 0) && (!src.l_setshort)) + dat += text("

\n5-DIGIT PASSCODE NOT SET.
ENTER NEW PASSCODE.
") + if (src.l_setshort) + dat += text("

\nALERT: MEMORY SYSTEM ERROR - 6040 201") + message = text("[]", src.code) + if (!src.locked) + message = "*****" + dat += text("


\n>[]
\n1-2-3
\n4-5-6
\n7-8-9
\nR-0-E
\n
", message, src, src, src, src, src, src, src, src, src, src, src, src) + user << browse(dat, "window=caselock;size=300x280") + +/obj/item/storage/secure/Topic(href, href_list) + ..() + if ((usr.stat || usr.restrained()) || (get_dist(src, usr) > 1)) + return + if (href_list["type"]) + if (href_list["type"] == "E") + if ((src.l_set == 0) && (length(src.code) == 5) && (!src.l_setshort) && (src.code != "ERROR")) + src.l_code = src.code + src.l_set = 1 + else if ((src.code == src.l_code) && (src.l_set == 1)) + src.locked = FALSE + cut_overlays() + add_overlay(icon_opened) + src.code = null + else + src.code = "ERROR" + else + if ((href_list["type"] == "R") && (!src.l_setshort)) + src.locked = TRUE + cut_overlays() + src.code = null + src.close(usr) + else + src.code += text("[]", sanitize_text(href_list["type"])) + if (length(src.code) > 5) + src.code = "ERROR" + src.add_fingerprint(usr) + for(var/mob/M in viewers(1, src.loc)) + if ((M.client && M.machine == src)) + src.attack_self(M) + return + return + +/obj/item/storage/secure/storage_contents_dump_act(obj/item/storage/src_object, mob/user) + if(locked) + to_chat(user, "It's locked!") + return null + return ..() + +/obj/item/storage/secure/can_be_inserted(obj/item/W, stop_messages = 0) + if(locked) + return 0 + return ..() + + +// ----------------------------- +// Secure Briefcase +// ----------------------------- +/obj/item/storage/secure/briefcase + name = "secure briefcase" + icon = 'icons/obj/storage.dmi' + icon_state = "secure" + item_state = "sec-case" + lefthand_file = 'icons/mob/inhands/equipment/briefcase_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/briefcase_righthand.dmi' + desc = "A large briefcase with a digital locking system." + force = 8 + hitsound = "swing_hit" + throw_speed = 2 + throw_range = 4 + w_class = WEIGHT_CLASS_BULKY + max_w_class = WEIGHT_CLASS_NORMAL + max_combined_w_class = 21 + attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked") + +/obj/item/storage/secure/briefcase/PopulateContents() + new /obj/item/paper(src) + new /obj/item/pen(src) + +/obj/item/storage/secure/briefcase/attack_hand(mob/user) + if ((src.loc == user) && (src.locked == 1)) + to_chat(usr, "[src] is locked and cannot be opened!") + add_fingerprint(user) + else + ..() + +//Syndie variant of Secure Briefcase. Contains space cash, slightly more robust. +/obj/item/storage/secure/briefcase/syndie + force = 15 + +/obj/item/storage/secure/briefcase/syndie/PopulateContents() + ..() + for(var/i = 0, i < storage_slots - 2, i++) + new /obj/item/stack/spacecash/c1000(src) + + +// ----------------------------- +// Secure Safe +// ----------------------------- + +/obj/item/storage/secure/safe + name = "secure safe" + icon = 'icons/obj/storage.dmi' + icon_state = "safe" + icon_opened = "safe0" + icon_locking = "safeb" + icon_sparking = "safespark" + force = 8 + w_class = WEIGHT_CLASS_GIGANTIC + max_w_class = 8 + anchored = TRUE + density = FALSE + cant_hold = list(/obj/item/storage/secure/briefcase) + +/obj/item/storage/secure/safe/PopulateContents() + new /obj/item/paper(src) + new /obj/item/pen(src) + +/obj/item/storage/secure/safe/attack_hand(mob/user) + return attack_self(user) + +/obj/item/storage/secure/safe/HoS + name = "head of security's safe" diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index 7f9209857f..5a2b52184a 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -1,571 +1,577 @@ -// External storage-related logic: -// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages -// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement -// /item/attackby() in /game/objects/items.dm - use_to_pickup and allow_quick_gather functionality -// -- c0 - - -/obj/item/storage - name = "storage" - icon = 'icons/obj/storage.dmi' - w_class = WEIGHT_CLASS_NORMAL - var/silent = 0 // No message on putting items in - var/list/can_hold = new/list() //Typecache of objects which this item can store (if set, it can't store anything else) - var/list/cant_hold = new/list() //Typecache of objects which this item can't store - var/list/is_seeing = new/list() //List of mobs which are currently seeing the contents of this item's storage - var/max_w_class = WEIGHT_CLASS_SMALL //Max size of objects that this object can store (in effect only if can_hold isn't set) - var/max_combined_w_class = 14 //The sum of the w_classes of all the items in this storage item. - var/storage_slots = 7 //The number of storage slots in this container. - var/obj/screen/storage/boxes = null - var/obj/screen/close/closer = null - var/use_to_pickup //Set this to make it possible to use this item in an inverse way, so you can have the item in your hand and click items on the floor to pick them up. - var/display_contents_with_number //Set this to make the storage item group contents of the same type and display them as a number. - var/allow_quick_empty //Set this variable to allow the object to have the 'empty' verb, which dumps all the contents on the floor. - var/allow_quick_gather //Set this variable to allow the object to have the 'toggle mode' verb, which quickly collects all items from a tile. - var/collection_mode = 1; //0 = pick one at a time, 1 = pick all on tile, 2 = pick all of a type - var/preposition = "in" // You put things 'in' a bag, but trays need 'on'. - var/rustle_jimmies = TRUE //Play the rustle sound on insertion - - -/obj/item/storage/MouseDrop(atom/over_object) - if(ismob(usr)) //all the check for item manipulation are in other places, you can safely open any storages as anything and its not buggy, i checked - var/mob/M = usr - - if(!over_object) - return - - if (istype(usr.loc, /obj/mecha)) // stops inventory actions in a mech - return - - // this must come before the screen objects only block, dunno why it wasn't before - if(over_object == M && M.CanReach(src,view_only = TRUE)) - orient2hud(M) - if(M.s_active) - M.s_active.close(M) - show_to(M) - return - - if(!M.incapacitated()) - if(!istype(over_object, /obj/screen)) - return content_can_dump(over_object, M) - - if(loc != usr || (loc && loc.loc == usr)) - return - - playsound(loc, "rustle", 50, 1, -5) - - if(istype(over_object, /obj/screen/inventory/hand)) - var/obj/screen/inventory/hand/H = over_object - M.putItemFromInventoryInHandIfPossible(src, H.held_index) - - add_fingerprint(usr) - - -/obj/item/storage/MouseDrop_T(atom/movable/O, mob/user) - if(isitem(O)) - var/obj/item/I = O - if(iscarbon(user) || isdrone(user)) - var/mob/living/L = user - if(!L.incapacitated() && I == L.get_active_held_item()) - if(can_be_inserted(I, 0)) - handle_item_insertion(I, 0 , L) - - -//Check if this storage can dump the items -/obj/item/storage/proc/content_can_dump(atom/dest_object, mob/user) - if(Adjacent(user) && dest_object.Adjacent(user)) - if(dest_object.storage_contents_dump_act(src, user)) - playsound(loc, "rustle", 50, 1, -5) - return 1 - return 0 - -//Object behaviour on storage dump -/obj/item/storage/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - var/list/things = src_object.contents.Copy() - var/datum/progressbar/progress = new(user, things.len, src) - while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(src, .proc/handle_mass_item_insertion, things, src_object, user, progress))) - sleep(1) - qdel(progress) - orient2hud(user) - src_object.orient2hud(user) - if(user.s_active) //refresh the HUD to show the transfered contents - user.s_active.close(user) - user.s_active.show_to(user) - return 1 - -/obj/item/storage/proc/handle_mass_item_insertion(list/things, obj/item/storage/src_object, mob/user, datum/progressbar/progress) - for(var/obj/item/I in things) - things -= I - if(I.loc != src_object) - continue - if(user.s_active != src_object) - if(I.on_found(user)) - break - if(can_be_inserted(I,0,user)) - handle_item_insertion(I, TRUE, user) - if (TICK_CHECK) - progress.update(progress.goal - things.len) - return TRUE - - progress.update(progress.goal - things.len) - return FALSE - -/obj/item/storage/proc/return_inv() - var/list/L = list() - L += contents - - for(var/obj/item/storage/S in src) - L += S.return_inv() - return L - - -/obj/item/storage/proc/show_to(mob/user) - if(!user.client) - return - if(user.s_active != src && (user.stat == CONSCIOUS)) - for(var/obj/item/I in src) - if(I.on_found(user)) - return - if(user.s_active) - user.s_active.hide_from(user) - user.client.screen |= boxes - user.client.screen |= closer - user.client.screen |= contents - user.s_active = src - is_seeing |= user - - -/obj/item/storage/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) - close_all() - return ..() - -/obj/item/storage/proc/hide_from(mob/user) - if(!user.client) - return - user.client.screen -= boxes - user.client.screen -= closer - user.client.screen -= contents - if(user.s_active == src) - user.s_active = null - is_seeing -= user - - -/obj/item/storage/proc/can_see_contents() - var/list/cansee = list() - for(var/mob/M in is_seeing) - if(M.s_active == src && M.client) - cansee |= M - else - is_seeing -= M - return cansee - - -/obj/item/storage/proc/close(mob/user) - hide_from(user) - user.s_active = null - - -/obj/item/storage/proc/close_all() - for(var/mob/M in can_see_contents()) - close(M) - . = 1 //returns 1 if any mobs actually got a close(M) call - - -//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right. -//The numbers are calculated from the bottom-left The bottom-left slot being 1,1. -/obj/item/storage/proc/orient_objs(tx, ty, mx, my) - var/cx = tx - var/cy = ty - boxes.screen_loc = "[tx]:,[ty] to [mx],[my]" - for(var/obj/O in contents) - O.screen_loc = "[cx],[cy]" - O.layer = ABOVE_HUD_LAYER - O.plane = ABOVE_HUD_PLANE - cx++ - if(cx > mx) - cx = tx - cy-- - closer.screen_loc = "[mx+1],[my]" - - -//This proc draws out the inventory and places the items on it. It uses the standard position. -/obj/item/storage/proc/standard_orient_objs(rows, cols, list/obj/item/display_contents) - var/cx = 4 - var/cy = 2+rows - boxes.screen_loc = "4:16,2:16 to [4+cols]:16,[2+rows]:16" - - if(display_contents_with_number) - for(var/datum/numbered_display/ND in display_contents) - ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE - ND.sample_object.screen_loc = "[cx]:16,[cy]:16" - ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]" - ND.sample_object.layer = ABOVE_HUD_LAYER - ND.sample_object.plane = ABOVE_HUD_PLANE - cx++ - if(cx > (4+cols)) - cx = 4 - cy-- - else - for(var/obj/O in contents) - O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip" - O.screen_loc = "[cx]:16,[cy]:16" - O.maptext = "" - O.layer = ABOVE_HUD_LAYER - O.plane = ABOVE_HUD_PLANE - cx++ - if(cx > (4+cols)) - cx = 4 - cy-- - closer.screen_loc = "[4+cols+1]:16,2:16" - - -/datum/numbered_display - var/obj/item/sample_object - var/number - -/datum/numbered_display/New(obj/item/sample) - if(!istype(sample)) - qdel(src) - sample_object = sample - number = 1 - - -//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing. -/obj/item/storage/proc/orient2hud(mob/user) - var/adjusted_contents = contents.len - - //Numbered contents display - var/list/datum/numbered_display/numbered_contents - if(display_contents_with_number) - numbered_contents = list() - adjusted_contents = 0 - for(var/obj/item/I in contents) - var/found = 0 - for(var/datum/numbered_display/ND in numbered_contents) - if(ND.sample_object.type == I.type) - ND.number++ - found = 1 - break - if(!found) - adjusted_contents++ - numbered_contents.Add( new/datum/numbered_display(I) ) - - //var/mob/living/carbon/human/H = user - var/row_num = 0 - var/col_count = min(7,storage_slots) -1 - if(adjusted_contents > 7) - row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. - standard_orient_objs(row_num, col_count, numbered_contents) - - -//This proc return 1 if the item can be picked up and 0 if it can't. -//Set the stop_messages to stop it from printing messages -/obj/item/storage/proc/can_be_inserted(obj/item/W, stop_messages = 0, mob/user) - if(!istype(W) || (W.flags_1 & ABSTRACT_1)) - return //Not an item - - if(loc == W) - return 0 //Means the item is already in the storage item - if(contents.len >= storage_slots) - if(!stop_messages) - to_chat(usr, "[src] is full, make some space!") - return 0 //Storage item is full - - if(can_hold.len) - if(!is_type_in_typecache(W, can_hold)) - if(!stop_messages) - to_chat(usr, "[src] cannot hold [W]!") - return 0 - - if(is_type_in_typecache(W, cant_hold)) //Check for specific items which this container can't hold. - if(!stop_messages) - to_chat(usr, "[src] cannot hold [W]!") - return 0 - - if(W.w_class > max_w_class) - if(!stop_messages) - to_chat(usr, "[W] is too big for [src]!") - return 0 - - var/sum_w_class = W.w_class - for(var/obj/item/I in contents) - sum_w_class += I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it. - - if(sum_w_class > max_combined_w_class) - if(!stop_messages) - to_chat(usr, "[W] won't fit in [src], make some space!") - return 0 - - if(W.w_class >= w_class && (istype(W, /obj/item/storage))) - if(!istype(src, /obj/item/storage/backpack/holding)) //bohs should be able to hold backpacks again. The override for putting a boh in a boh is in backpack.dm. - if(!stop_messages) - to_chat(usr, "[src] cannot hold [W] as it's a storage item of the same size!") - return 0 //To prevent the stacking of same sized storage items. - - if(W.flags_1 & NODROP_1) //SHOULD be handled in unEquip, but better safe than sorry. - to_chat(usr, "\the [W] is stuck to your hand, you can't put it in \the [src]!") - return 0 - - return 1 - - -//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted() -//The stop_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once, -//such as when picking up all the items on a tile with one click. -/obj/item/storage/proc/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) - if(!istype(W)) - return 0 - if(usr) - if(!usr.transferItemToLoc(W, src)) - return 0 - else - W.forceMove(src) - if(silent) - prevent_warning = 1 - if(W.pulledby) - W.pulledby.stop_pulling() - W.on_enter_storage(src) - if(usr) - if(usr.client && usr.s_active != src) - usr.client.screen -= W - if(usr.observers && usr.observers.len) - for(var/M in usr.observers) - var/mob/dead/observe = M - if(observe.client && observe.s_active != src) - observe.client.screen -= W - - add_fingerprint(usr) - if(rustle_jimmies && !prevent_warning) - playsound(src.loc, "rustle", 50, 1, -5) - - if(!prevent_warning) - for(var/mob/M in viewers(usr, null)) - if(M == usr) - to_chat(usr, "You put [W] [preposition]to [src].") - else if(in_range(M, usr)) //If someone is standing close enough, they can tell what it is... - M.show_message("[usr] puts [W] [preposition]to [src].", 1) - else if(W && W.w_class >= 3) //Otherwise they can only see large or normal items from a distance... - M.show_message("[usr] puts [W] [preposition]to [src].", 1) - - orient2hud(usr) - for(var/mob/M in can_see_contents()) - show_to(M) - W.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt - update_icon() - return 1 - - -//Call this proc to handle the removal of an item from the storage item. The item will be moved to the atom sent as new_target -/obj/item/storage/proc/remove_from_storage(obj/item/W, atom/new_location) - if(!istype(W)) - return 0 - - if(istype(src, /obj/item/storage/fancy)) - var/obj/item/storage/fancy/F = src - F.update_icon(1) - - for(var/mob/M in can_see_contents()) - if(M.client) - M.client.screen -= W - - if(ismob(loc)) - var/mob/M = loc - W.dropped(M) - W.layer = initial(W.layer) - W.plane = initial(W.plane) - W.forceMove(new_location) - - for(var/mob/M in can_see_contents()) - orient2hud(M) - show_to(M) - - if(W.maptext) - W.maptext = "" - W.on_exit_storage(src) - update_icon() - W.mouse_opacity = initial(W.mouse_opacity) - return 1 - -/obj/item/storage/deconstruct(disassembled = TRUE) - var/drop_loc = loc - if(ismob(loc)) - drop_loc = get_turf(src) - for(var/obj/item/I in contents) - remove_from_storage(I, drop_loc) - qdel(src) - -//This proc is called when you want to place an item into the storage item. -/obj/item/storage/attackby(obj/item/W, mob/user, params) - ..() - if(istype(W, /obj/item/hand_labeler)) - var/obj/item/hand_labeler/labeler = W - if(labeler.mode) - return 0 - . = 1 //no afterattack - if(iscyborg(user)) - return //Robots can't interact with storage items. - - if(!can_be_inserted(W, 0 , user)) - if(contents.len >= storage_slots) //don't use items on the backpack if they don't fit - return 1 - return 0 - - handle_item_insertion(W, 0 , user) - - -/obj/item/storage/attack_hand(mob/user) - if(user.s_active == src && loc == user) //if you're already looking inside the storage item - user.s_active.close(user) - close(user) - return - - if(rustle_jimmies) - playsound(loc, "rustle", 50, 1, -5) - - if(ishuman(user)) - var/mob/living/carbon/human/H = user - if(H.l_store == src && !H.get_active_held_item()) //Prevents opening if it's in a pocket. - H.put_in_hands(src) - H.l_store = null - return - if(H.r_store == src && !H.get_active_held_item()) - H.put_in_hands(src) - H.r_store = null - return - - orient2hud(user) - if(loc == user) - if(user.s_active) - user.s_active.close(user) - show_to(user) - else - ..() - for(var/mob/M in range(1)) - if(M.s_active == src) - close(M) - add_fingerprint(user) - -/obj/item/storage/attack_paw(mob/user) - return attack_hand(user) - -/obj/item/storage/verb/toggle_gathering_mode() - set name = "Switch Gathering Method" - set category = "Object" - - if(usr.stat || !usr.canmove || usr.restrained()) - return - - collection_mode = (collection_mode+1)%3 - switch (collection_mode) - if(2) - to_chat(usr, "[src] now picks up all items of a single type at once.") - if(1) - to_chat(usr, "[src] now picks up all items in a tile at once.") - if(0) - to_chat(usr, "[src] now picks up one item at a time.") - -// Empty all the contents onto the current turf -/obj/item/storage/verb/quick_empty() - set name = "Empty Contents" - set category = "Object" - - if((!ishuman(usr) && (loc != usr)) || usr.stat || usr.restrained() ||!usr.canmove) - return - var/turf/T = get_turf(src) - var/list/things = contents.Copy() - var/datum/progressbar/progress = new(usr, things.len, T) - while (do_after(usr, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress))) - sleep(1) - qdel(progress) - -/obj/item/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress) - for(var/obj/item/I in things) - things -= I - if (I.loc != src) - continue - remove_from_storage(I, target) - if (TICK_CHECK) - progress.update(progress.goal - things.len) - return TRUE - - progress.update(progress.goal - things.len) - return FALSE - -// Empty all the contents onto the current turf, without checking the user's status. -/obj/item/storage/proc/do_quick_empty() - var/turf/T = get_turf(src) - if(usr) - hide_from(usr) - for(var/obj/item/I in contents) - remove_from_storage(I, T) - - -/obj/item/storage/Initialize(mapload) - . = ..() - - can_hold = typecacheof(can_hold) - cant_hold = typecacheof(cant_hold) - - if(allow_quick_empty) - verbs += /obj/item/storage/verb/quick_empty - else - verbs -= /obj/item/storage/verb/quick_empty - - if(allow_quick_gather) - verbs += /obj/item/storage/verb/toggle_gathering_mode - else - verbs -= /obj/item/storage/verb/toggle_gathering_mode - - boxes = new /obj/screen/storage() - boxes.name = "storage" - boxes.master = src - boxes.icon_state = "block" - boxes.screen_loc = "7,7 to 10,8" - boxes.layer = HUD_LAYER - boxes.plane = HUD_PLANE - closer = new /obj/screen/close() - closer.master = src - closer.icon_state = "backpack_close" - closer.layer = ABOVE_HUD_LAYER - closer.plane = ABOVE_HUD_PLANE - orient2hud() - - PopulateContents() - - -/obj/item/storage/Destroy() - for(var/obj/O in contents) - O.mouse_opacity = initial(O.mouse_opacity) - - close_all() - qdel(boxes) - qdel(closer) - return ..() - - -/obj/item/storage/emp_act(severity) - if(!isliving(loc)) - for(var/obj/O in contents) - O.emp_act(severity) - ..() - - -/obj/item/storage/attack_self(mob/user) - //Clicking on itself will empty it, if it has the verb to do that. - if(user.get_active_held_item() == src) - if(verbs.Find(/obj/item/storage/verb/quick_empty)) - quick_empty() - -/obj/item/storage/handle_atom_del(atom/A) - if(A in contents) - usr = null - remove_from_storage(A, null) - -/obj/item/storage/contents_explosion(severity, target) - for(var/atom/A in contents) - A.ex_act(severity, target) - CHECK_TICK - -//Cyberboss says: "USE THIS TO FILL IT, NOT INITIALIZE OR NEW" - -/obj/item/storage/proc/PopulateContents() +// External storage-related logic: +// /mob/proc/ClickOn() in /_onclick/click.dm - clicking items in storages +// /mob/living/Move() in /modules/mob/living/living.dm - hiding storage boxes on mob movement +// /item/attackby() in /game/objects/items.dm - use_to_pickup and allow_quick_gather functionality +// -- c0 + + +/obj/item/storage + name = "storage" + icon = 'icons/obj/storage.dmi' + w_class = WEIGHT_CLASS_NORMAL + var/silent = 0 // No message on putting items in + var/list/can_hold = new/list() //Typecache of objects which this item can store (if set, it can't store anything else) + var/list/cant_hold = new/list() //Typecache of objects which this item can't store + var/list/is_seeing = new/list() //List of mobs which are currently seeing the contents of this item's storage + var/max_w_class = WEIGHT_CLASS_SMALL //Max size of objects that this object can store (in effect only if can_hold isn't set) + var/max_combined_w_class = 14 //The sum of the w_classes of all the items in this storage item. + var/storage_slots = 7 //The number of storage slots in this container. + var/obj/screen/storage/boxes = null + var/obj/screen/close/closer = null + var/use_to_pickup //Set this to make it possible to use this item in an inverse way, so you can have the item in your hand and click items on the floor to pick them up. + var/display_contents_with_number //Set this to make the storage item group contents of the same type and display them as a number. + var/allow_quick_empty //Set this variable to allow the object to have the 'empty' verb, which dumps all the contents on the floor. + var/allow_quick_gather //Set this variable to allow the object to have the 'toggle mode' verb, which quickly collects all items from a tile. + var/collection_mode = 1; //0 = pick one at a time, 1 = pick all on tile, 2 = pick all of a type + var/preposition = "in" // You put things 'in' a bag, but trays need 'on'. + var/rustle_jimmies = TRUE //Play the rustle sound on insertion + + +/obj/item/storage/MouseDrop(atom/over_object) + if(ismob(usr)) //all the check for item manipulation are in other places, you can safely open any storages as anything and its not buggy, i checked + var/mob/M = usr + + if(!over_object) + return + + if (istype(usr.loc, /obj/mecha)) // stops inventory actions in a mech + return + + // this must come before the screen objects only block, dunno why it wasn't before + if(over_object == M && M.CanReach(src,view_only = TRUE)) + orient2hud(M) + if(M.s_active) + M.s_active.close(M) + show_to(M) + return + + if(!M.incapacitated()) + if(!istype(over_object, /obj/screen)) + return dump_content_at(over_object, M) + + if(loc != usr || (loc && loc.loc == usr)) + return + + playsound(loc, "rustle", 50, 1, -5) + + if(istype(over_object, /obj/screen/inventory/hand)) + var/obj/screen/inventory/hand/H = over_object + M.putItemFromInventoryInHandIfPossible(src, H.held_index) + + add_fingerprint(usr) + + +/obj/item/storage/MouseDrop_T(atom/movable/O, mob/user) + if(isitem(O)) + var/obj/item/I = O + if(iscarbon(user) || isdrone(user)) + var/mob/living/L = user + if(!L.incapacitated() && I == L.get_active_held_item()) + if(can_be_inserted(I, 0)) + handle_item_insertion(I, 0 , L) + + +/obj/item/storage/get_dumping_location(obj/item/storage/source,mob/user) + return src + +//Tries to dump content +/obj/item/storage/proc/dump_content_at(atom/dest_object, mob/user) + var/atom/dump_destination = dest_object.get_dumping_location() + if(Adjacent(user) && dump_destination && user.Adjacent(dump_destination)) + if(dump_destination.storage_contents_dump_act(src, user)) + playsound(loc, "rustle", 50, 1, -5) + return 1 + return 0 + +//Object behaviour on storage dump +/obj/item/storage/storage_contents_dump_act(obj/item/storage/src_object, mob/user) + var/list/things = src_object.contents.Copy() + var/datum/progressbar/progress = new(user, things.len, src) + while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(src, .proc/handle_mass_item_insertion, things, src_object, user, progress))) + sleep(1) + qdel(progress) + orient2hud(user) + src_object.orient2hud(user) + if(user.s_active) //refresh the HUD to show the transfered contents + user.s_active.close(user) + user.s_active.show_to(user) + return 1 + +/obj/item/storage/proc/handle_mass_item_insertion(list/things, obj/item/storage/src_object, mob/user, datum/progressbar/progress) + for(var/obj/item/I in things) + things -= I + if(I.loc != src_object) + continue + if(user.s_active != src_object) + if(I.on_found(user)) + break + if(can_be_inserted(I,0,user)) + handle_item_insertion(I, TRUE, user) + if (TICK_CHECK) + progress.update(progress.goal - things.len) + return TRUE + + progress.update(progress.goal - things.len) + return FALSE + +/obj/item/storage/proc/return_inv() + var/list/L = list() + L += contents + + for(var/obj/item/storage/S in src) + L += S.return_inv() + return L + + +/obj/item/storage/proc/show_to(mob/user) + if(!user.client) + return + if(user.s_active != src && (user.stat == CONSCIOUS)) + for(var/obj/item/I in src) + if(I.on_found(user)) + return + if(user.s_active) + user.s_active.hide_from(user) + user.client.screen |= boxes + user.client.screen |= closer + user.client.screen |= contents + user.s_active = src + is_seeing |= user + + +/obj/item/storage/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) + close_all() + return ..() + +/obj/item/storage/proc/hide_from(mob/user) + if(!user.client) + return + user.client.screen -= boxes + user.client.screen -= closer + user.client.screen -= contents + if(user.s_active == src) + user.s_active = null + is_seeing -= user + + +/obj/item/storage/proc/can_see_contents() + var/list/cansee = list() + for(var/mob/M in is_seeing) + if(M.s_active == src && M.client) + cansee |= M + else + is_seeing -= M + return cansee + + +/obj/item/storage/proc/close(mob/user) + hide_from(user) + user.s_active = null + + +/obj/item/storage/proc/close_all() + for(var/mob/M in can_see_contents()) + close(M) + . = 1 //returns 1 if any mobs actually got a close(M) call + + +//This proc draws out the inventory and places the items on it. tx and ty are the upper left tile and mx, my are the bottm right. +//The numbers are calculated from the bottom-left The bottom-left slot being 1,1. +/obj/item/storage/proc/orient_objs(tx, ty, mx, my) + var/cx = tx + var/cy = ty + boxes.screen_loc = "[tx]:,[ty] to [mx],[my]" + for(var/obj/O in contents) + O.screen_loc = "[cx],[cy]" + O.layer = ABOVE_HUD_LAYER + O.plane = ABOVE_HUD_PLANE + cx++ + if(cx > mx) + cx = tx + cy-- + closer.screen_loc = "[mx+1],[my]" + + +//This proc draws out the inventory and places the items on it. It uses the standard position. +/obj/item/storage/proc/standard_orient_objs(rows, cols, list/obj/item/display_contents) + var/cx = 4 + var/cy = 2+rows + boxes.screen_loc = "4:16,2:16 to [4+cols]:16,[2+rows]:16" + + if(display_contents_with_number) + for(var/datum/numbered_display/ND in display_contents) + ND.sample_object.mouse_opacity = MOUSE_OPACITY_OPAQUE + ND.sample_object.screen_loc = "[cx]:16,[cy]:16" + ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]" + ND.sample_object.layer = ABOVE_HUD_LAYER + ND.sample_object.plane = ABOVE_HUD_PLANE + cx++ + if(cx > (4+cols)) + cx = 4 + cy-- + else + for(var/obj/O in contents) + O.mouse_opacity = MOUSE_OPACITY_OPAQUE //This is here so storage items that spawn with contents correctly have the "click around item to equip" + O.screen_loc = "[cx]:16,[cy]:16" + O.maptext = "" + O.layer = ABOVE_HUD_LAYER + O.plane = ABOVE_HUD_PLANE + cx++ + if(cx > (4+cols)) + cx = 4 + cy-- + closer.screen_loc = "[4+cols+1]:16,2:16" + + +/datum/numbered_display + var/obj/item/sample_object + var/number + +/datum/numbered_display/New(obj/item/sample) + if(!istype(sample)) + qdel(src) + sample_object = sample + number = 1 + + +//This proc determines the size of the inventory to be displayed. Please touch it only if you know what you're doing. +/obj/item/storage/proc/orient2hud(mob/user) + var/adjusted_contents = contents.len + + //Numbered contents display + var/list/datum/numbered_display/numbered_contents + if(display_contents_with_number) + numbered_contents = list() + adjusted_contents = 0 + for(var/obj/item/I in contents) + var/found = 0 + for(var/datum/numbered_display/ND in numbered_contents) + if(ND.sample_object.type == I.type) + ND.number++ + found = 1 + break + if(!found) + adjusted_contents++ + numbered_contents.Add( new/datum/numbered_display(I) ) + + //var/mob/living/carbon/human/H = user + var/row_num = 0 + var/col_count = min(7,storage_slots) -1 + if(adjusted_contents > 7) + row_num = round((adjusted_contents-1) / 7) // 7 is the maximum allowed width. + standard_orient_objs(row_num, col_count, numbered_contents) + + +//This proc return 1 if the item can be picked up and 0 if it can't. +//Set the stop_messages to stop it from printing messages +/obj/item/storage/proc/can_be_inserted(obj/item/W, stop_messages = 0, mob/user) + if(!istype(W) || (W.flags_1 & ABSTRACT_1)) + return //Not an item + + if(loc == W) + return 0 //Means the item is already in the storage item + if(contents.len >= storage_slots) + if(!stop_messages) + to_chat(usr, "[src] is full, make some space!") + return 0 //Storage item is full + + if(can_hold.len) + if(!is_type_in_typecache(W, can_hold)) + if(!stop_messages) + to_chat(usr, "[src] cannot hold [W]!") + return 0 + + if(is_type_in_typecache(W, cant_hold)) //Check for specific items which this container can't hold. + if(!stop_messages) + to_chat(usr, "[src] cannot hold [W]!") + return 0 + + if(W.w_class > max_w_class) + if(!stop_messages) + to_chat(usr, "[W] is too big for [src]!") + return 0 + + var/sum_w_class = W.w_class + for(var/obj/item/I in contents) + sum_w_class += I.w_class //Adds up the combined w_classes which will be in the storage item if the item is added to it. + + if(sum_w_class > max_combined_w_class) + if(!stop_messages) + to_chat(usr, "[W] won't fit in [src], make some space!") + return 0 + + if(W.w_class >= w_class && (istype(W, /obj/item/storage))) + if(!istype(src, /obj/item/storage/backpack/holding)) //bohs should be able to hold backpacks again. The override for putting a boh in a boh is in backpack.dm. + if(!stop_messages) + to_chat(usr, "[src] cannot hold [W] as it's a storage item of the same size!") + return 0 //To prevent the stacking of same sized storage items. + + if(W.flags_1 & NODROP_1) //SHOULD be handled in unEquip, but better safe than sorry. + to_chat(usr, "\the [W] is stuck to your hand, you can't put it in \the [src]!") + return 0 + + return 1 + + +//This proc handles items being inserted. It does not perform any checks of whether an item can or can't be inserted. That's done by can_be_inserted() +//The stop_warning parameter will stop the insertion message from being displayed. It is intended for cases where you are inserting multiple items at once, +//such as when picking up all the items on a tile with one click. +/obj/item/storage/proc/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) + if(!istype(W)) + return 0 + if(usr) + if(!usr.transferItemToLoc(W, src)) + return 0 + else + W.forceMove(src) + if(silent) + prevent_warning = 1 + if(W.pulledby) + W.pulledby.stop_pulling() + W.on_enter_storage(src) + if(usr) + if(usr.client && usr.s_active != src) + usr.client.screen -= W + if(usr.observers && usr.observers.len) + for(var/M in usr.observers) + var/mob/dead/observe = M + if(observe.client && observe.s_active != src) + observe.client.screen -= W + + add_fingerprint(usr) + if(rustle_jimmies && !prevent_warning) + playsound(src.loc, "rustle", 50, 1, -5) + + if(!prevent_warning) + for(var/mob/M in viewers(usr, null)) + if(M == usr) + to_chat(usr, "You put [W] [preposition]to [src].") + else if(in_range(M, usr)) //If someone is standing close enough, they can tell what it is... + M.show_message("[usr] puts [W] [preposition]to [src].", 1) + else if(W && W.w_class >= 3) //Otherwise they can only see large or normal items from a distance... + M.show_message("[usr] puts [W] [preposition]to [src].", 1) + + orient2hud(usr) + for(var/mob/M in can_see_contents()) + show_to(M) + W.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt + update_icon() + return 1 + + +//Call this proc to handle the removal of an item from the storage item. The item will be moved to the atom sent as new_target +/obj/item/storage/proc/remove_from_storage(obj/item/W, atom/new_location) + if(!istype(W)) + return 0 + + if(istype(src, /obj/item/storage/fancy)) + var/obj/item/storage/fancy/F = src + F.update_icon(1) + + for(var/mob/M in can_see_contents()) + if(M.client) + M.client.screen -= W + + if(ismob(loc)) + var/mob/M = loc + W.dropped(M) + W.layer = initial(W.layer) + W.plane = initial(W.plane) + W.forceMove(new_location) + + for(var/mob/M in can_see_contents()) + orient2hud(M) + show_to(M) + + if(W.maptext) + W.maptext = "" + W.on_exit_storage(src) + update_icon() + W.mouse_opacity = initial(W.mouse_opacity) + return 1 + +/obj/item/storage/deconstruct(disassembled = TRUE) + var/drop_loc = loc + if(ismob(loc)) + drop_loc = get_turf(src) + for(var/obj/item/I in contents) + remove_from_storage(I, drop_loc) + qdel(src) + +//This proc is called when you want to place an item into the storage item. +/obj/item/storage/attackby(obj/item/W, mob/user, params) + ..() + if(istype(W, /obj/item/hand_labeler)) + var/obj/item/hand_labeler/labeler = W + if(labeler.mode) + return 0 + . = 1 //no afterattack + if(iscyborg(user)) + return //Robots can't interact with storage items. + + if(!can_be_inserted(W, 0 , user)) + if(contents.len >= storage_slots) //don't use items on the backpack if they don't fit + return 1 + return 0 + + handle_item_insertion(W, 0 , user) + +/obj/item/storage/AllowDrop() + return TRUE + +/obj/item/storage/attack_hand(mob/user) + if(user.s_active == src && loc == user) //if you're already looking inside the storage item + user.s_active.close(user) + close(user) + return + + if(rustle_jimmies) + playsound(loc, "rustle", 50, 1, -5) + + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.l_store == src && !H.get_active_held_item()) //Prevents opening if it's in a pocket. + H.put_in_hands(src) + H.l_store = null + return + if(H.r_store == src && !H.get_active_held_item()) + H.put_in_hands(src) + H.r_store = null + return + + orient2hud(user) + if(loc == user) + if(user.s_active) + user.s_active.close(user) + show_to(user) + else + ..() + for(var/mob/M in range(1)) + if(M.s_active == src) + close(M) + add_fingerprint(user) + +/obj/item/storage/attack_paw(mob/user) + return attack_hand(user) + +/obj/item/storage/verb/toggle_gathering_mode() + set name = "Switch Gathering Method" + set category = "Object" + + if(usr.stat || !usr.canmove || usr.restrained()) + return + + collection_mode = (collection_mode+1)%3 + switch (collection_mode) + if(2) + to_chat(usr, "[src] now picks up all items of a single type at once.") + if(1) + to_chat(usr, "[src] now picks up all items in a tile at once.") + if(0) + to_chat(usr, "[src] now picks up one item at a time.") + +// Empty all the contents onto the current turf +/obj/item/storage/verb/quick_empty() + set name = "Empty Contents" + set category = "Object" + + if((!ishuman(usr) && (loc != usr)) || usr.stat || usr.restrained() ||!usr.canmove) + return + var/turf/T = get_turf(src) + var/list/things = contents.Copy() + var/datum/progressbar/progress = new(usr, things.len, T) + while (do_after(usr, 10, TRUE, T, FALSE, CALLBACK(src, .proc/mass_remove_from_storage, T, things, progress))) + sleep(1) + qdel(progress) + +/obj/item/storage/proc/mass_remove_from_storage(atom/target, list/things, datum/progressbar/progress) + for(var/obj/item/I in things) + things -= I + if (I.loc != src) + continue + remove_from_storage(I, target) + if (TICK_CHECK) + progress.update(progress.goal - things.len) + return TRUE + + progress.update(progress.goal - things.len) + return FALSE + +// Empty all the contents onto the current turf, without checking the user's status. +/obj/item/storage/proc/do_quick_empty() + var/turf/T = get_turf(src) + if(usr) + hide_from(usr) + for(var/obj/item/I in contents) + remove_from_storage(I, T) + + +/obj/item/storage/Initialize(mapload) + . = ..() + + can_hold = typecacheof(can_hold) + cant_hold = typecacheof(cant_hold) + + if(allow_quick_empty) + verbs += /obj/item/storage/verb/quick_empty + else + verbs -= /obj/item/storage/verb/quick_empty + + if(allow_quick_gather) + verbs += /obj/item/storage/verb/toggle_gathering_mode + else + verbs -= /obj/item/storage/verb/toggle_gathering_mode + + boxes = new /obj/screen/storage() + boxes.name = "storage" + boxes.master = src + boxes.icon_state = "block" + boxes.screen_loc = "7,7 to 10,8" + boxes.layer = HUD_LAYER + boxes.plane = HUD_PLANE + closer = new /obj/screen/close() + closer.master = src + closer.icon_state = "backpack_close" + closer.layer = ABOVE_HUD_LAYER + closer.plane = ABOVE_HUD_PLANE + orient2hud() + + PopulateContents() + + +/obj/item/storage/Destroy() + for(var/obj/O in contents) + O.mouse_opacity = initial(O.mouse_opacity) + + close_all() + qdel(boxes) + qdel(closer) + return ..() + + +/obj/item/storage/emp_act(severity) + if(!isliving(loc)) + for(var/obj/O in contents) + O.emp_act(severity) + ..() + + +/obj/item/storage/attack_self(mob/user) + //Clicking on itself will empty it, if it has the verb to do that. + if(user.get_active_held_item() == src) + if(verbs.Find(/obj/item/storage/verb/quick_empty)) + quick_empty() + +/obj/item/storage/handle_atom_del(atom/A) + if(A in contents) + usr = null + remove_from_storage(A, null) + +/obj/item/storage/contents_explosion(severity, target) + for(var/atom/A in contents) + A.ex_act(severity, target) + CHECK_TICK + +//Cyberboss says: "USE THIS TO FILL IT, NOT INITIALIZE OR NEW" + +/obj/item/storage/proc/PopulateContents() diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index 8fbb03797f..1f3668f283 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -1,228 +1,230 @@ -/obj - var/crit_fail = FALSE - animate_movement = 2 - var/throwforce = 0 - var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! - - var/damtype = BRUTE - var/force = 0 - - var/list/armor +/obj + var/crit_fail = FALSE + animate_movement = 2 + var/throwforce = 0 + var/in_use = 0 // If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING! + + var/damtype = BRUTE + var/force = 0 + + var/list/armor var/obj_integrity //defaults to max_integrity - var/max_integrity = 500 - var/integrity_failure = 0 //0 if we have no special broken behavior - - var/resistance_flags = 0 // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF - - var/acid_level = 0 //how much acid is on that obj - - var/being_shocked = FALSE - - var/on_blueprints = FALSE //Are we visible on the station blueprints at roundstart? - var/force_blueprints = FALSE //forces the obj to be on the blueprints, regardless of when it was created. - - var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset. - var/unique_rename = FALSE // can you customize the description/name of the thing? - var/current_skin //Has the item been reskinned? - var/list/unique_reskin //List of options to reskin. - var/dangerous_possession = FALSE //Admin possession yes/no - -/obj/vv_edit_var(vname, vval) - switch(vname) - if("dangerous_possession") - return FALSE - if("control_object") - var/obj/O = vval - if(istype(O) && O.dangerous_possession) - return FALSE - ..() - -/obj/Initialize() - . = ..() - if (!armor) - armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0) + var/max_integrity = 500 + var/integrity_failure = 0 //0 if we have no special broken behavior + + var/resistance_flags = 0 // INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF + + var/acid_level = 0 //how much acid is on that obj + + var/being_shocked = FALSE + + var/on_blueprints = FALSE //Are we visible on the station blueprints at roundstart? + var/force_blueprints = FALSE //forces the obj to be on the blueprints, regardless of when it was created. + + var/persistence_replacement //have something WAY too amazing to live to the next round? Set a new path here. Overuse of this var will make me upset. + var/unique_rename = FALSE // can you customize the description/name of the thing? + var/current_skin //Has the item been reskinned? + var/list/unique_reskin //List of options to reskin. + var/dangerous_possession = FALSE //Admin possession yes/no + +/obj/vv_edit_var(vname, vval) + switch(vname) + if("dangerous_possession") + return FALSE + if("control_object") + var/obj/O = vval + if(istype(O) && O.dangerous_possession) + return FALSE + ..() + +/obj/Initialize() + . = ..() + if (!armor) + armor = list(melee = 0, bullet = 0, laser = 0, energy = 0, bomb = 0, bio = 0, rad = 0, fire = 0, acid = 0) if(obj_integrity == null) obj_integrity = max_integrity - if(on_blueprints && isturf(loc)) - var/turf/T = loc - if(force_blueprints) - T.add_blueprints(src) - else - T.add_blueprints_preround(src) - -/obj/Destroy(force=FALSE) - if(!istype(src, /obj/machinery)) - STOP_PROCESSING(SSobj, src) // TODO: Have a processing bitflag to reduce on unnecessary loops through the processing lists - SStgui.close_uis(src) - . = ..() - -/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) - ..() + if(on_blueprints && isturf(loc)) + var/turf/T = loc + if(force_blueprints) + T.add_blueprints(src) + else + T.add_blueprints_preround(src) + +/obj/Destroy(force=FALSE) + if(!istype(src, /obj/machinery)) + STOP_PROCESSING(SSobj, src) // TODO: Have a processing bitflag to reduce on unnecessary loops through the processing lists + SStgui.close_uis(src) + . = ..() + +/obj/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback) + ..() if(flags_2 & FROZEN_2) - visible_message("[src] shatters into a million pieces!") - qdel(src) - -/obj/assume_air(datum/gas_mixture/giver) - if(loc) - return loc.assume_air(giver) - else - return null - -/obj/remove_air(amount) - if(loc) - return loc.remove_air(amount) - else - return null - -/obj/return_air() - if(loc) - return loc.return_air() - else - return null - -/obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_request) - //Return: (NONSTANDARD) - // null if object handles breathing logic for lifeform - // datum/air_group to tell lifeform to process using that breath return - //DEFAULT: Take air from turf to give to have mob process - - if(breath_request>0) - var/datum/gas_mixture/environment = return_air() - var/breath_percentage = BREATH_VOLUME / environment.return_volume() - return remove_air(environment.total_moles() * breath_percentage) - else - return null - -/obj/proc/updateUsrDialog() - if(in_use) - var/is_in_use = 0 - var/list/nearby = viewers(1, src) - for(var/mob/M in nearby) - if ((M.client && M.machine == src)) - is_in_use = 1 - src.attack_hand(M) - if(isAI(usr) || iscyborg(usr) || IsAdminGhost(usr)) - if (!(usr in nearby)) - if (usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh. - is_in_use = 1 - src.attack_ai(usr) - - // check for TK users - - if(ishuman(usr)) - var/mob/living/carbon/human/H = usr - if(!(usr in nearby)) - if(usr.client && usr.machine==src) - if(H.dna.check_mutation(TK)) - is_in_use = 1 - src.attack_hand(usr) - in_use = is_in_use - -/obj/proc/updateDialog() - // Check that people are actually using the machine. If not, don't update anymore. - if(in_use) - var/list/nearby = viewers(1, src) - var/is_in_use = 0 - for(var/mob/M in nearby) - if ((M.client && M.machine == src)) - is_in_use = 1 - src.interact(M) - var/ai_in_use = AutoUpdateAI(src) - - if(!ai_in_use && !is_in_use) - in_use = 0 - - -/obj/attack_ghost(mob/user) - if(ui_interact(user) != -1) - return - ..() - -/obj/proc/container_resist(mob/living/user) - return - -/obj/proc/update_icon() - return - -/mob/proc/unset_machine() - if(machine) - machine.on_unset_machine(src) - machine = null - -//called when the user unsets the machine. -/atom/movable/proc/on_unset_machine(mob/user) - return - -/mob/proc/set_machine(obj/O) - if(src.machine) - unset_machine() - src.machine = O - if(istype(O)) - O.in_use = 1 - -/obj/item/proc/updateSelfDialog() - var/mob/M = src.loc - if(istype(M) && M.client && M.machine == src) - src.attack_self(M) - -/obj/proc/hide(h) - return - -/obj/singularity_pull(S, current_size) - if(!anchored || current_size >= STAGE_FIVE) - step_towards(src,S) - -/obj/get_spans() - return ..() | SPAN_ROBOT - -/obj/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - var/turf/T = get_turf(src) - return T.storage_contents_dump_act(src_object, user) - -/obj/proc/CanAStarPass() - . = !density - -/obj/proc/check_uplink_validity() - return 1 - -/obj/proc/on_mob_move(dir, mob, oldLoc) - return - -/obj/proc/on_mob_turn(dir, mob) - return - + visible_message("[src] shatters into a million pieces!") + qdel(src) + +/obj/assume_air(datum/gas_mixture/giver) + if(loc) + return loc.assume_air(giver) + else + return null + +/obj/remove_air(amount) + if(loc) + return loc.remove_air(amount) + else + return null + +/obj/return_air() + if(loc) + return loc.return_air() + else + return null + +/obj/proc/handle_internal_lifeform(mob/lifeform_inside_me, breath_request) + //Return: (NONSTANDARD) + // null if object handles breathing logic for lifeform + // datum/air_group to tell lifeform to process using that breath return + //DEFAULT: Take air from turf to give to have mob process + + if(breath_request>0) + var/datum/gas_mixture/environment = return_air() + var/breath_percentage = BREATH_VOLUME / environment.return_volume() + return remove_air(environment.total_moles() * breath_percentage) + else + return null + +/obj/proc/updateUsrDialog() + if(in_use) + var/is_in_use = 0 + var/list/nearby = viewers(1, src) + for(var/mob/M in nearby) + if ((M.client && M.machine == src)) + is_in_use = 1 + src.attack_hand(M) + if(isAI(usr) || iscyborg(usr) || IsAdminGhost(usr)) + if (!(usr in nearby)) + if (usr.client && usr.machine==src) // && M.machine == src is omitted because if we triggered this by using the dialog, it doesn't matter if our machine changed in between triggering it and this - the dialog is probably still supposed to refresh. + is_in_use = 1 + src.attack_ai(usr) + + // check for TK users + + if(ishuman(usr)) + var/mob/living/carbon/human/H = usr + if(!(usr in nearby)) + if(usr.client && usr.machine==src) + if(H.dna.check_mutation(TK)) + is_in_use = 1 + src.attack_hand(usr) + in_use = is_in_use + +/obj/proc/updateDialog() + // Check that people are actually using the machine. If not, don't update anymore. + if(in_use) + var/list/nearby = viewers(1, src) + var/is_in_use = 0 + for(var/mob/M in nearby) + if ((M.client && M.machine == src)) + is_in_use = 1 + src.interact(M) + var/ai_in_use = AutoUpdateAI(src) + + if(!ai_in_use && !is_in_use) + in_use = 0 + + +/obj/attack_ghost(mob/user) + if(ui_interact(user) != -1) + return + ..() + +/obj/proc/container_resist(mob/living/user) + return + +/obj/proc/update_icon() + return + +/mob/proc/unset_machine() + if(machine) + machine.on_unset_machine(src) + machine = null + +//called when the user unsets the machine. +/atom/movable/proc/on_unset_machine(mob/user) + return + +/mob/proc/set_machine(obj/O) + if(src.machine) + unset_machine() + src.machine = O + if(istype(O)) + O.in_use = 1 + +/obj/item/proc/updateSelfDialog() + var/mob/M = src.loc + if(istype(M) && M.client && M.machine == src) + src.attack_self(M) + +/obj/proc/hide(h) + return + +/obj/singularity_pull(S, current_size) + if(!anchored || current_size >= STAGE_FIVE) + step_towards(src,S) + +/obj/get_spans() + return ..() | SPAN_ROBOT + +/obj/storage_contents_dump_act(obj/item/storage/src_object, mob/user) + return + +/obj/get_dumping_location(obj/item/storage/source,mob/user) + return get_turf(src) + +/obj/proc/CanAStarPass() + . = !density + +/obj/proc/check_uplink_validity() + return 1 + +/obj/proc/on_mob_move(dir, mob, oldLoc) + return + +/obj/proc/on_mob_turn(dir, mob) + return + /obj/proc/intercept_user_move(dir, mob, newLoc, oldLoc) return -/obj/vv_get_dropdown() - . = ..() - .["Delete all of type"] = "?_src_=vars;delall=\ref[src]" - -/obj/examine(mob/user) - ..() - if(unique_rename) - to_chat(user, "Use a pen on it to rename it or change its description.") - if(unique_reskin && !current_skin) - to_chat(user, "Alt-click it to reskin it.") - -/obj/AltClick(mob/user) - . = ..() - if(unique_reskin && !current_skin && in_range(user,src)) - if(user.incapacitated()) - to_chat(user, "You can't do that right now!") - return - reskin_obj(user) - -/obj/proc/reskin_obj(mob/M) - if(!LAZYLEN(unique_reskin)) - return - var/choice = input(M,"Warning, you can only reskin [src] once!","Reskin Object") as null|anything in unique_reskin - if(!QDELETED(src) && choice && !current_skin && !M.incapacitated() && in_range(M,src)) - if(!unique_reskin[choice]) - return - current_skin = choice - icon_state = unique_reskin[choice] - to_chat(M, "[src] is now skinned as '[choice].'") - -/obj/proc/gang_contraband_value() - return 0 +/obj/vv_get_dropdown() + . = ..() + .["Delete all of type"] = "?_src_=vars;delall=\ref[src]" + +/obj/examine(mob/user) + ..() + if(unique_rename) + to_chat(user, "Use a pen on it to rename it or change its description.") + if(unique_reskin && !current_skin) + to_chat(user, "Alt-click it to reskin it.") + +/obj/AltClick(mob/user) + . = ..() + if(unique_reskin && !current_skin && in_range(user,src)) + if(user.incapacitated()) + to_chat(user, "You can't do that right now!") + return + reskin_obj(user) + +/obj/proc/reskin_obj(mob/M) + if(!LAZYLEN(unique_reskin)) + return + var/choice = input(M,"Warning, you can only reskin [src] once!","Reskin Object") as null|anything in unique_reskin + if(!QDELETED(src) && choice && !current_skin && !M.incapacitated() && in_range(M,src)) + if(!unique_reskin[choice]) + return + current_skin = choice + icon_state = unique_reskin[choice] + to_chat(M, "[src] is now skinned as '[choice].'") + +/obj/proc/gang_contraband_value() + return 0 diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index daa29df061..5d6e6f3d77 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -137,8 +137,8 @@ new mineral(loc) qdel(src) -/obj/structure/falsewall/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - return 0 +/obj/structure/falsewall/get_dumping_location(obj/item/storage/source,mob/user) + return null /obj/structure/falsewall/examine_status(mob/user) //So you can't detect falsewalls by examine. return null diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index e091454ac6..6a3bdb81b4 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -226,8 +226,8 @@ C.powernet.load += C.powernet.avail * 0.0375 // you can gain up to 3.5 via the 4x upgrades power is halved by the pole so thats 2x then 1X then .5X for 3.5x the 3 bounces shock. return ..() -/obj/structure/grille/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - return 0 +/obj/structure/grille/get_dumping_location(obj/item/storage/source,mob/user) + return null /obj/structure/grille/broken // Pre-broken grilles for map placement icon_state = "brokengrille" diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm index 0e44a88fef..57774a5754 100644 --- a/code/game/turfs/simulated/walls.dm +++ b/code/game/turfs/simulated/walls.dm @@ -263,8 +263,8 @@ if(.) ChangeTurf(/turf/closed/wall/clockwork) -/turf/closed/wall/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - return 0 +/turf/closed/wall/get_dumping_location(obj/item/storage/source,mob/user) + return null /turf/closed/wall/acid_act(acidpwr, acid_volume) if(explosion_block >= 2) diff --git a/code/modules/recycling/disposal-unit.dm b/code/modules/recycling/disposal-unit.dm index 0bb6df7ca9..14ebec8128 100644 --- a/code/modules/recycling/disposal-unit.dm +++ b/code/modules/recycling/disposal-unit.dm @@ -247,6 +247,9 @@ AM.forceMove(T) ..() +/obj/machinery/disposal/get_dumping_location(obj/item/storage/source,mob/user) + return src + //How disposal handles getting a storage dump from a storage object /obj/machinery/disposal/storage_contents_dump_act(obj/item/storage/src_object, mob/user) for(var/obj/item/I in src_object) diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index dbfd6d1ed2..f22961ae15 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -44,12 +44,13 @@ If you create T5+ please take a pass at gene_modder.dm [L40]. Max_values MUST fi pshoom_or_beepboopblorpzingshadashwoosh = 'sound/items/pshoom.ogg' alt_sound = 'sound/items/pshoom_2.ogg' -/obj/item/storage/part_replacer/bluespace/content_can_dump(atom/dest_object, mob/user) +/obj/item/storage/part_replacer/bluespace/dump_content_at(atom/dest_object, mob/user) if(Adjacent(user)) - if(get_dist(user, dest_object) < 8) - if(dest_object.storage_contents_dump_act(src, user)) + var/atom/dumping_location = dest_object.get_dumping_location() + if(get_dist(user, dumping_location) < 8) + if(dumping_location.storage_contents_dump_act(src, user)) play_rped_sound() - user.Beam(dest_object,icon_state="rped_upgrade",time=5) + user.Beam(dumping_location,icon_state="rped_upgrade",time=5) return 1 to_chat(user, "The [src.name] buzzes.") playsound(src, 'sound/machines/buzz-sigh.ogg', 50, 0)