diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index f5d0ec3bd7..87894dd4d7 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -52,7 +52,6 @@ var/safe = FALSE //Is the area teleport-safe: no space / radiation / aggresive mobs / other dangers var/no_air = null - var/list/related // the other areas of the same type as this var/parallax_movedir = 0 @@ -88,27 +87,10 @@ GLOBAL_LIST_EMPTY(teleportlocs) // === -// Added to fix mech fabs 05/2013 ~Sayu -// This is necessary due to lighting subareas. If you were to go in assuming that things in -// the same logical /area have the parent /area object... well, you would be mistaken. If you -// want to find machines, mobs, etc, in the same logical area, you will need to check all the -// related areas. This returns a master contents list to assist in that. -/proc/area_contents(area/A) - if(!istype(A)) - return null - var/list/contents = list() - for(var/area/LSA in A.related) - contents += LSA.contents - return contents - - - - /area/Initialize() icon_state = "" layer = AREA_LAYER uid = ++global_uid - related = list(src) map_name = name // Save the initial (the name set in the map) name of the area. canSmoothWithAreas = typecacheof(canSmoothWithAreas) @@ -195,11 +177,6 @@ GLOBAL_LIST_EMPTY(teleportlocs) /area/proc/atmosalert(danger_level, obj/source) if(danger_level != atmosalm) if (danger_level==2) - var/list/cameras = list() - for(var/area/RA in related) - for (var/item in RA.cameras) - var/obj/machinery/camera/C = item - cameras += C for (var/item in GLOB.silicon_mobs) var/mob/living/silicon/aiPlayer = item @@ -254,18 +231,12 @@ GLOBAL_LIST_EMPTY(teleportlocs) if(always_unpowered == 1) //no fire alarms in space/asteroid return - var/list/cameras = list() - - for(var/area/RA in related) - if (!( RA.fire )) - RA.set_fire_alarm_effect() - RA.ModifyFiredoors(FALSE) - for(var/item in RA.firealarms) - var/obj/machinery/firealarm/F = item - F.update_icon() - for (var/item in RA.cameras) - var/obj/machinery/camera/C = item - cameras += C + if (!fire) + set_fire_alarm_effect() + ModifyFiredoors(FALSE) + for(var/item in firealarms) + var/obj/machinery/firealarm/F = item + F.update_icon() for (var/item in GLOB.alert_consoles) var/obj/machinery/computer/station_alert/a = item @@ -283,15 +254,14 @@ GLOBAL_LIST_EMPTY(teleportlocs) START_PROCESSING(SSobj, src) /area/proc/firereset(obj/source) - for(var/area/RA in related) - if (RA.fire) - RA.fire = 0 - RA.mouse_opacity = MOUSE_OPACITY_TRANSPARENT - RA.updateicon() - RA.ModifyFiredoors(TRUE) - for(var/item in RA.firealarms) - var/obj/machinery/firealarm/F = item - F.update_icon() + if (fire) + fire = 0 + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + updateicon() + ModifyFiredoors(TRUE) + for(var/item in firealarms) + var/obj/machinery/firealarm/F = item + F.update_icon() for (var/item in GLOB.silicon_mobs) var/mob/living/silicon/aiPlayer = item @@ -310,8 +280,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) /area/process() if(firedoors_last_closed_on + 100 < world.time) //every 10 seconds - for(var/area/RA in related) - RA.ModifyFiredoors(FALSE) + ModifyFiredoors(FALSE) /area/proc/close_and_lock_door(obj/machinery/door/DOOR) set waitfor = FALSE @@ -323,17 +292,11 @@ GLOBAL_LIST_EMPTY(teleportlocs) if(always_unpowered == 1) //no burglar alarms in space/asteroid return - var/list/cameras = list() - - for(var/area/RA in related) - //Trigger alarm effect - RA.set_fire_alarm_effect() - //Lockdown airlocks - for(var/obj/machinery/door/DOOR in RA) - close_and_lock_door(DOOR) - for (var/item in RA.cameras) - var/obj/machinery/camera/C = item - cameras += C + //Trigger alarm effect + set_fire_alarm_effect() + //Lockdown airlocks + for(var/obj/machinery/door/DOOR in src) + close_and_lock_door(DOOR) for (var/i in GLOB.silicon_mobs) var/mob/living/silicon/SILICON = i @@ -429,10 +392,9 @@ GLOBAL_LIST_EMPTY(teleportlocs) // called when power status changes /area/proc/power_change() - for(var/area/RA in related) - for(var/obj/machinery/M in RA) // for each machine in the area - M.power_change() // reverify power status (to update icons etc.) - RA.updateicon() + for(var/obj/machinery/M in src) // for each machine in the area + M.power_change() // reverify power status (to update icons etc.) + updateicon() /area/proc/usage(chan) var/used = 0 @@ -553,3 +515,7 @@ GLOBAL_LIST_EMPTY(teleportlocs) /area/drop_location() CRASH("Bad op: area/drop_location() called") + +// A hook so areas can modify the incoming args +/area/proc/PlaceOnTopReact(list/new_baseturfs, turf/fake_turf_type, flags) + return flags \ No newline at end of file diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm index 7d0283e104..073e7714b2 100644 --- a/code/game/area/areas/shuttles.dm +++ b/code/game/area/areas/shuttles.dm @@ -16,6 +16,13 @@ canSmoothWithAreas = type . = ..() +/area/shuttle/PlaceOnTopReact(list/new_baseturfs, turf/fake_turf_type, flags) + . = ..() + if(length(new_baseturfs) > 1 || fake_turf_type) + return // More complicated larger changes indicate this isn't a player + if(ispath(new_baseturfs[1], /turf/open/floor/plating)) + new_baseturfs.Insert(1, /turf/baseturf_skipover/shuttle) + ////////////////////////////Multi-area shuttles//////////////////////////// ////////////////////////////Syndicate infiltrator//////////////////////////// diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 6c15daeb1e..6b4e882235 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -387,13 +387,31 @@ return FALSE /atom/proc/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - return 0 + if(GetComponent(/datum/component/storage)) + return component_storage_contents_dump_act(src_object, user) + return FALSE + +/atom/proc/component_storage_contents_dump_act(datum/component/storage/src_object, mob/user) + var/list/things = src_object.contents() + var/datum/progressbar/progress = new(user, things.len, src) + GET_COMPONENT(STR, /datum/component/storage) + while (do_after(user, 10, TRUE, src, FALSE, CALLBACK(STR, /datum/component/storage.proc/handle_mass_item_insertion, things, src_object, user, progress))) + stoplag(1) + qdel(progress) + to_chat(user, "You dump as much of [src_object.parent]'s contents into [STR.insert_preposition]to [src] as you can.") + STR.orient2hud(user) + src_object.orient2hud(user) + if(user.active_storage) //refresh the HUD to show the transfered contents + user.active_storage.close(user) + user.active_storage.show_to(user) + return TRUE /atom/proc/get_dumping_location(obj/item/storage/source,mob/user) return null //This proc is called on the location of an atom when the atom is Destroy()'d /atom/proc/handle_atom_del(atom/A) + SendSignal(COMSIG_ATOM_CONTENTS_DEL, A) //called when the turf the atom resides on is ChangeTurfed /atom/proc/HandleTurfChange(turf/T) @@ -526,8 +544,8 @@ /atom/Entered(atom/movable/AM, atom/oldLoc) SendSignal(COMSIG_ATOM_ENTERED, AM, oldLoc) -/atom/Exited(atom/movable/AM) - SendSignal(COMSIG_ATOM_EXITED, AM) +/atom/Exited(atom/movable/AM, atom/newLoc) + SendSignal(COMSIG_ATOM_EXITED, AM, newLoc) /atom/proc/return_temperature() return diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 95412c6a7b..67f34cef74 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -492,12 +492,12 @@ if(spin) SpinAnimation(5, 1) + SendSignal(COMSIG_MOVABLE_THROW, TT, spin) SSthrowing.processing[src] = TT if (SSthrowing.state == SS_PAUSED && length(SSthrowing.currentrun)) SSthrowing.currentrun[src] = TT TT.tick() - /atom/movable/proc/handle_buckled_mob_movement(newloc,direct) for(var/m in buckled_mobs) var/mob/living/buckled_mob = m @@ -514,6 +514,13 @@ return 1 return ..() +// called when this atom is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. +/atom/movable/proc/on_exit_storage(datum/component/storage/concrete/S) + return + +// called when this atom is added into a storage item, which is passed on as S. The loc variable is already set to the storage item. +/atom/movable/proc/on_enter_storage(datum/component/storage/concrete/S) + return /atom/movable/proc/get_spacemove_backup() var/atom/movable/dense_object_backup @@ -538,7 +545,7 @@ /atom/movable/proc/relay_container_resist(mob/living/user, obj/O) return -// CITADEL CHANGE - adds final_pixel_y and final_pixel_x to do_attack_animation args // maybe not needed anymore we'll try it + /atom/movable/proc/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect) if(!no_effect && (visual_effect_icon || used_item)) do_item_attack_animation(A, visual_effect_icon, used_item) @@ -675,9 +682,8 @@ if(ismob(loc)) var/mob/M = loc M.transferItemToLoc(src, targetturf, TRUE) //nodrops disks when? - else if(istype(loc, /obj/item/storage)) - var/obj/item/storage/S = loc - S.remove_from_storage(src, targetturf) + else if(loc.SendSignal(COMSIG_CONTAINS_STORAGE)) + loc.SendSignal(COMSIG_TRY_STORAGE_TAKE, src, targetturf, TRUE) else forceMove(targetturf) // move the disc, so ghosts remain orbiting it even if it's "destroyed" @@ -708,7 +714,6 @@ return FALSE - /* Language procs */ /atom/movable/proc/get_language_holder(shadow=TRUE) if(language_holder) diff --git a/code/game/gamemodes/clown_ops/clown_weapons.dm b/code/game/gamemodes/clown_ops/clown_weapons.dm index 3b74d796be..6488a98d7d 100644 --- a/code/game/gamemodes/clown_ops/clown_weapons.dm +++ b/code/game/gamemodes/clown_ops/clown_weapons.dm @@ -21,7 +21,7 @@ strip_delay = 70 resistance_flags = NONE permeability_coefficient = 0.05 - pockets = /obj/item/storage/internal/pocket/shoes + pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes //The super annoying version /obj/item/clothing/shoes/clown_shoes/banana_shoes/combat @@ -32,7 +32,7 @@ strip_delay = 70 resistance_flags = NONE permeability_coefficient = 0.05 - pockets = /obj/item/storage/internal/pocket/shoes + pocket_storage_component_path = /datum/component/storage/concrete/pockets/shoes always_noslip = TRUE var/max_recharge = 3000 //30 peels worth var/recharge_rate = 34 //about 1/3 of a peel per tick diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index b678f8cd0e..8c162c600e 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -573,6 +573,8 @@ GLOBAL_LIST_EMPTY(possible_items_special) return captured_amount >= target_amount +//Changeling Objectives + /datum/objective/absorb /datum/objective/absorb/proc/gen_amount_goal(lowbound = 4, highbound = 6) @@ -604,7 +606,47 @@ GLOBAL_LIST_EMPTY(possible_items_special) absorbedcount += changeling.absorbedcount return absorbedcount >= target_amount +/datum/objective/absorb_most + explanation_text = "Extract more compatible genomes than any other Changeling." +/datum/objective/absorb_most/check_completion() + var/list/datum/mind/owners = get_owners() + var/absorbedcount = 0 + for(var/datum/mind/M in owners) + if(!M) + continue + var/datum/antagonist/changeling/changeling = M.has_antag_datum(/datum/antagonist/changeling) + if(!changeling || !changeling.stored_profiles) + continue + absorbedcount += changeling.absorbedcount + + for(var/datum/antagonist/changeling/changeling2 in GLOB.antagonists) + if(!changeling2.owner || !changeling2.stored_profiles || changeling2.absorbedcount < absorbedcount) + continue + return FALSE + return TRUE + +/datum/objective/absorb_changeling + explanation_text = "Absorb another Changeling." + +/datum/objective/absorb_changeling/check_completion() + var/list/datum/mind/owners = get_owners() + for(var/datum/mind/M in owners) + if(!M) + continue + var/datum/antagonist/changeling/changeling = M.has_antag_datum(/datum/antagonist/changeling) + if(!changeling) + continue + var/total_genetic_points = changeling.geneticpoints + + for(var/obj/effect/proc_holder/changeling/p in changeling.purchasedpowers) + total_genetic_points += p.dna_cost + + if(total_genetic_points > initial(changeling.geneticpoints)) + return TRUE + return FALSE + +//End Changeling Objectives /datum/objective/destroy martyr_compatible = 1 @@ -829,3 +871,6 @@ GLOBAL_LIST_EMPTY(possible_items_special) /datum/objective/changeling_team_objective/impersonate_department/impersonate_heads explanation_text = "Have X or more heads of staff escape on the shuttle disguised as heads, while the real heads are dead" command_staff_only = TRUE + + + diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 17d4906c42..61d5dbe5f6 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -413,10 +413,10 @@ Class Procs: var/obj/item/stack/SN = new SB.merge_type(null,used_amt) component_parts += SN else - W.remove_from_storage(B, src) - component_parts += B - B.moveToNullspace() - W.handle_item_insertion(A, 1) + if(W.SendSignal(COMSIG_TRY_STORAGE_TAKE, B, src)) + component_parts += B + B.moveToNullspace() + W.SendSignal(COMSIG_TRY_STORAGE_INSERT, A, null, null, TRUE) component_parts -= A to_chat(user, "[A.name] replaced with [B.name].") shouldplaysound = 1 //Only play the sound when parts are actually replaced! diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm index 68f279cc29..4d9acb0586 100644 --- a/code/game/machinery/computer/_computer.dm +++ b/code/game/machinery/computer/_computer.dm @@ -10,7 +10,6 @@ max_integrity = 200 integrity_failure = 100 armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 40, "acid" = 20) - var/processing = FALSE var/brightness_on = 2 var/icon_keyboard = "generic_key" var/icon_screen = "generic" diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index d129ebc233..e90f69bf23 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -536,7 +536,7 @@ playsound(loc, 'sound/weapons/genhit.ogg', 100, 1) var/turf/open/space/T for(T in orange(1, src)) - T.ChangeTurf(/turf/open/floor/plating/) + T.PlaceOnTop(/turf/open/floor/plating) else say("Something slams into the floor around [src] - luckily, it didn't get through!") playsound(loc, 'sound/effects/bang.ogg', 50, 1) diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 6f0294fe67..edbf181927 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -173,11 +173,14 @@ GLOBAL_DATUM_INIT(crewmonitor, /datum/crewmonitor, new) results[++results.len] = list("name" = name, "assignment" = assignment, "ijob" = ijob, "life_status" = life_status, "oxydam" = oxydam, "toxdam" = toxdam, "burndam" = burndam, "brutedam" = brutedam, "area" = area, "pos_x" = pos_x, "pos_y" = pos_y, "can_track" = H.can_track(null)) - data_by_z["[z]"] = results + data_by_z["[z]"] = sortTim(results,/proc/sensor_compare) last_update["[z]"] = world.time return results +/proc/sensor_compare(list/a,list/b) + return a["ijob"] - b["ijob"] + /datum/crewmonitor/ui_act(action,params) var/mob/living/silicon/ai/AI = usr if(!istype(AI)) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 09f59fd003..7aab26dc63 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -212,8 +212,8 @@ req_components[path] -= used_amt else added_components[part] = path - replacer.remove_from_storage(part, src) - req_components[path]-- + if(replacer.SendSignal(COMSIG_TRY_STORAGE_TAKE, part, src)) + req_components[path]-- for(var/obj/item/part in added_components) if(istype(part,/obj/item/stack)) diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm index 348d238f4c..69621adc84 100644 --- a/code/game/machinery/doors/airlock_types.dm +++ b/code/game/machinery/doors/airlock_types.dm @@ -88,6 +88,9 @@ opacity = 0 glass = TRUE +/obj/machinery/door/airlock/engineering/glass/critical + critical_machine = TRUE //stops greytide virus from opening & bolting doors in critical positions, such as the SM chamber. + /obj/machinery/door/airlock/security/glass opacity = 0 glass = TRUE @@ -112,6 +115,9 @@ opacity = 0 glass = TRUE +/obj/machinery/door/airlock/atmos/glass/critical + critical_machine = TRUE //stops greytide virus from opening & bolting doors in critical positions, such as the SM chamber. + /obj/machinery/door/airlock/science/glass opacity = 0 glass = TRUE diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index efc8682313..bb05111f19 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -287,9 +287,7 @@ A = A.loc if (!( istype(A, /area) )) return - for(var/area/RA in A.related) - RA.partyreset() - return + A.partyreset() /obj/machinery/firealarm/partyalarm/alarm() if (stat & (NOPOWER|BROKEN)) @@ -298,9 +296,7 @@ A = A.loc if (!( istype(A, /area) )) return - for(var/area/RA in A.related) - RA.partyalert() - return + A.partyalert() /obj/machinery/firealarm/partyalarm/ui_data(mob/user) . = ..() diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index f51fcdede7..d6b35136b6 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -349,21 +349,8 @@ Possible to do for anyone motivated enough: if(!istype(AI)) AI = null - if(!QDELETED(master) && !master.incapacitated() && master.client && (!AI || AI.eyeobj))//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector. - if(is_operational())//If the machine has power. - if(AI) //ais are range based - if(get_dist(AI.eyeobj, src) <= holo_range) - continue - else - var/obj/machinery/holopad/pad_close = get_closest_atom(/obj/machinery/holopad, holopads, AI.eyeobj) - if(get_dist(pad_close, AI.eyeobj) <= holo_range) - var/obj/effect/overlay/holo_pad_hologram/h = masters[master] - unset_holo(master) - pad_close.set_holo(master, h) - continue - else - continue - clear_holo(master)//If not, we want to get rid of the hologram. + if(!is_operational() || !validate_user(master)) + clear_holo(master) if(outgoing_call) outgoing_call.Check() @@ -484,16 +471,48 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ SetLightsAndPower() return TRUE +//Try to transfer hologram to another pad that can project on T +/obj/machinery/holopad/proc/transfer_to_nearby_pad(turf/T,mob/holo_owner) + var/obj/effect/overlay/holo_pad_hologram/h = masters[holo_owner] + if(!h || h.HC) //Holocalls can't change source. + return FALSE + for(var/pad in holopads) + var/obj/machinery/holopad/another = pad + if(another == src) + continue + if(another.validate_location(T)) + unset_holo(holo_owner) + another.set_holo(holo_owner, h) + return TRUE + return FALSE + +/obj/machinery/holopad/proc/validate_user(mob/living/user) + if(QDELETED(user) || user.incapacitated() || !user.client) + return FALSE + return TRUE + +//Can we display holos there +//Area check instead of line of sight check because this is a called a lot if AI wants to move around. +/obj/machinery/holopad/proc/validate_location(turf/T,check_los = FALSE) + if(T.z == z && get_dist(T, src) <= holo_range && T.loc == get_area(src)) + return TRUE + else + return FALSE + /obj/machinery/holopad/proc/move_hologram(mob/living/user, turf/new_turf) if(LAZYLEN(masters) && masters[user]) - var/area/holo_area = get_area(src) - if(new_turf.loc in holo_area.related) - var/obj/effect/overlay/holo_pad_hologram/holo = masters[user] - step_to(holo, new_turf) - holo.forceMove(new_turf) - update_holoray(user, new_turf) - else - clear_holo(user) + var/obj/effect/overlay/holo_pad_hologram/holo = masters[user] + var/transfered = FALSE + if(!validate_location(new_turf)) + if(!transfer_to_nearby_pad(new_turf,user)) + clear_holo(user) + return FALSE + else + transfered = TRUE + //All is good. + holo.forceMove(new_turf) + if(!transfered) + update_holoray(user,new_turf) return TRUE diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index fb90f1b5b4..c93f67b7d7 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -41,13 +41,12 @@ . = ..() on = !on - for(var/area/A in area.related) - A.lightswitch = on - A.updateicon() + area.lightswitch = on + area.updateicon() - for(var/obj/machinery/light_switch/L in A) - L.on = on - L.updateicon() + for(var/obj/machinery/light_switch/L in area) + L.on = on + L.updateicon() area.power_change() diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 706e14cae6..6c3687f6b8 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -317,7 +317,7 @@ add_overlay(picture_state) #undef CHARS_PER_LINE -#undef FOND_SIZE +#undef FONT_SIZE #undef FONT_COLOR #undef FONT_STYLE #undef SCROLL_SPEED diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm deleted file mode 100755 index 12b55c4205..0000000000 --- a/code/game/machinery/vending.dm +++ /dev/null @@ -1,1225 +0,0 @@ -#define STANDARD_CHARGE 1 -#define CONTRABAND_CHARGE 2 -#define COIN_CHARGE 3 - -/datum/data/vending_product - var/product_name = "generic" - var/product_path = null - var/amount = 0 - var/max_amount = 0 - var/display_color = "blue" - - -/obj/machinery/vending - name = "\improper Vendomat" - desc = "A generic vending machine." - icon = 'icons/obj/vending.dmi' - icon_state = "generic" - layer = BELOW_OBJ_LAYER - anchored = TRUE - density = TRUE - verb_say = "beeps" - verb_ask = "beeps" - verb_exclaim = "beeps" - max_integrity = 300 - integrity_failure = 100 - armor = list("melee" = 20, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 70) - circuit = /obj/item/circuitboard/machine/vendor - var/active = 1 //No sales pitches if off! - var/vend_ready = 1 //Are we ready to vend?? Is it time?? - - // To be filled out at compile time - var/list/products = list() //For each, use the following pattern: - var/list/contraband = list() //list(/type/path = amount, /type/path2 = amount2) - var/list/premium = list() //No specified amount = only one in stock - - var/product_slogans = "" //String of slogans separated by semicolons, optional - var/product_ads = "" //String of small ad messages in the vending screen - random chance - var/list/product_records = list() - var/list/hidden_records = list() - var/list/coin_records = list() - var/list/slogan_list = list() - var/list/small_ads = list() //Small ad messages in the vending screen - random chance of popping up whenever you open it - var/vend_reply //Thank you for shopping! - var/last_reply = 0 - var/last_slogan = 0 //When did we last pitch? - var/slogan_delay = 6000 //How long until we can pitch again? - var/icon_vend //Icon_state when vending! - var/icon_deny //Icon_state when vending! - var/seconds_electrified = 0 //Shock customers like an airlock. - var/shoot_inventory = 0 //Fire items at customers! We're broken! - var/shoot_inventory_chance = 2 - var/shut_up = 0 //Stop spouting those godawful pitches! - var/extended_inventory = 0 //can we access the hidden inventory? - var/scan_id = 1 - var/obj/item/coin/coin - var/obj/item/stack/spacecash/bill - - var/dish_quants = list() //used by the snack machine's custom compartment to count dishes. - - var/obj/item/vending_refill/refill_canister = null //The type of refill canisters used by this machine. - var/refill_count = 3 //The number of canisters the vending machine uses - -/obj/machinery/vending/Initialize() - var/build_inv = FALSE - if(!refill_canister) - circuit = null - build_inv = TRUE - . = ..() - wires = new /datum/wires/vending(src) - if(build_inv) //non-constructable vending machine - build_inventory(products) - build_inventory(contraband, 1) - build_inventory(premium, 0, 1) - - slogan_list = splittext(product_slogans, ";") - // So not all machines speak at the exact same time. - // The first time this machine says something will be at slogantime + this random value, - // so if slogantime is 10 minutes, it will say it at somewhere between 10 and 20 minutes after the machine is crated. - last_slogan = world.time + rand(0, slogan_delay) - power_change() - - -/obj/machinery/vending/Destroy() - QDEL_NULL(wires) - QDEL_NULL(coin) - QDEL_NULL(bill) - return ..() - -/obj/machinery/vending/snack/Destroy() - for(var/obj/item/reagent_containers/food/snacks/S in contents) - S.forceMove(get_turf(src)) - return ..() - -/obj/machinery/vending/RefreshParts() //Better would be to make constructable child - if(component_parts) - product_records = list() - hidden_records = list() - coin_records = list() - build_inventory(products, start_empty = 1) - build_inventory(contraband, 1, start_empty = 1) - build_inventory(premium, 0, 1, start_empty = 1) - for(var/obj/item/vending_refill/VR in component_parts) - refill_inventory(VR, product_records, STANDARD_CHARGE) - refill_inventory(VR, coin_records, COIN_CHARGE) - refill_inventory(VR, hidden_records, CONTRABAND_CHARGE) - - -/obj/machinery/vending/deconstruct(disassembled = TRUE) - if(!refill_canister) //the non constructable vendors drop metal instead of a machine frame. - if(!(flags_1 & NODECONSTRUCT_1)) - new /obj/item/stack/sheet/metal(loc, 3) - qdel(src) - else - ..() - -/obj/machinery/vending/obj_break(damage_flag) - if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1)) - var/dump_amount = 0 - for(var/datum/data/vending_product/R in product_records) - if(R.amount <= 0) //Try to use a record that actually has something to dump. - continue - var/dump_path = R.product_path - if(!dump_path) - continue - - while(R.amount>0) - var/obj/O = new dump_path(loc) - step(O, pick(GLOB.alldirs)) //we only drop 20% of the total of each products and spread it - R.amount -= 5 //around to not fill the turf with too many objects. - dump_amount++ - if(dump_amount > 15) //so we don't drop too many items (e.g. ClothesMate) - break - stat |= BROKEN - icon_state = "[initial(icon_state)]-broken" - -/obj/machinery/vending/proc/build_inventory(list/productlist, hidden=0, req_coin=0, start_empty = null) - for(var/typepath in productlist) - var/amount = productlist[typepath] - if(isnull(amount)) - amount = 0 - - var/atom/temp = typepath - var/datum/data/vending_product/R = new /datum/data/vending_product() - R.product_name = initial(temp.name) - R.product_path = typepath - if(!start_empty) - R.amount = amount - R.max_amount = amount - R.display_color = pick("red","blue","green") - - if(hidden) - hidden_records += R - else if(req_coin) - coin_records += R - else - product_records += R - -/obj/machinery/vending/proc/refill_inventory(obj/item/vending_refill/refill, datum/data/vending_product/machine, var/charge_type = STANDARD_CHARGE) - var/total = 0 - var/to_restock = 0 - - for(var/datum/data/vending_product/machine_content in machine) - if(machine_content.amount == 0 && refill.charges[charge_type] > 0) - machine_content.amount++ - refill.charges[charge_type]-- - total++ - to_restock += machine_content.max_amount - machine_content.amount - if(to_restock <= refill.charges[charge_type]) - for(var/datum/data/vending_product/machine_content in machine) - machine_content.amount = machine_content.max_amount - refill.charges[charge_type] -= to_restock - total += to_restock - else - var/tmp_charges = refill.charges[charge_type] - for(var/datum/data/vending_product/machine_content in machine) - if(refill.charges[charge_type] == 0) - break - var/restock = CEILING(((machine_content.max_amount - machine_content.amount)/to_restock)*tmp_charges, 1) - if(restock > refill.charges[charge_type]) - restock = refill.charges[charge_type] - machine_content.amount += restock - refill.charges[charge_type] -= restock - total += restock - return total - -/obj/machinery/vending/snack/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/reagent_containers/food/snacks)) - if(!compartment_access_check(user)) - return - var/obj/item/reagent_containers/food/snacks/S = W - if(!S.junkiness) - if(!iscompartmentfull(user)) - if(!user.transferItemToLoc(W, src)) - return - food_load(W) - to_chat(user, "You insert [W] into [src]'s chef compartment.") - else - to_chat(user, "[src]'s chef compartment does not accept junk food.") - - else if(istype(W, /obj/item/storage/bag/tray)) - if(!compartment_access_check(user)) - return - var/obj/item/storage/T = W - var/loaded = 0 - var/denied_items = 0 - for(var/obj/item/reagent_containers/food/snacks/S in T.contents) - if(iscompartmentfull(user)) - break - if(!S.junkiness) - T.remove_from_storage(S, src) - food_load(S) - loaded++ - else - denied_items++ - if(denied_items) - to_chat(user, "[src] refuses some items.") - if(loaded) - to_chat(user, "You insert [loaded] dishes into [src]'s chef compartment.") - updateUsrDialog() - return - - else - return ..() - -/obj/machinery/vending/snack/proc/compartment_access_check(user) - req_access_txt = chef_compartment_access - if(!allowed(user) && !(obj_flags & EMAGGED) && scan_id) - to_chat(user, "[src]'s chef compartment blinks red: Access denied.") - req_access_txt = "0" - return 0 - req_access_txt = "0" - return 1 - -/obj/machinery/vending/snack/proc/iscompartmentfull(mob/user) - if(contents.len >= 30) // no more than 30 dishes can fit inside - to_chat(user, "[src]'s chef compartment is full.") - return 1 - return 0 - -/obj/machinery/vending/snack/proc/food_load(obj/item/reagent_containers/food/snacks/S) - if(dish_quants[S.name]) - dish_quants[S.name]++ - else - dish_quants[S.name] = 1 - sortList(dish_quants) - -/obj/machinery/vending/crowbar_act(mob/living/user, obj/item/I) - if(!component_parts) - return FALSE - default_deconstruction_crowbar(I) - return TRUE - -/obj/machinery/vending/wrench_act(mob/living/user, obj/item/I) - if(panel_open) - default_unfasten_wrench(user, I, time = 60) - return TRUE - -/obj/machinery/vending/screwdriver_act(mob/living/user, obj/item/I) - if(anchored) - default_deconstruction_screwdriver(user, icon_state, icon_state, I) - cut_overlays() - if(panel_open) - add_overlay("[initial(icon_state)]-panel") - updateUsrDialog() - else - to_chat(user, "You must first secure [src].") - return TRUE - -/obj/machinery/vending/attackby(obj/item/I, mob/user, params) - if(panel_open && is_wire_tool(I)) - wires.interact(user) - return - else if(istype(I, /obj/item/coin)) - if(coin) - to_chat(user, "[src] already has [coin] inserted") - return - if(bill) - to_chat(user, "[src] already has [bill] inserted") - return - if(!premium.len) - to_chat(user, "[src] doesn't have a coin slot.") - return - if(!user.transferItemToLoc(I, src)) - return - coin = I - to_chat(user, "You insert [I] into [src].") - return - else if(istype(I, /obj/item/stack/spacecash)) - if(coin) - to_chat(user, "[src] already has [coin] inserted") - return - if(bill) - to_chat(user, "[src] already has [bill] inserted") - return - var/obj/item/stack/S = I - if(!premium.len) - to_chat(user, "[src] doesn't have a bill slot.") - return - S.use(1) - bill = new S.type(src, 1) - to_chat(user, "You insert [I] into [src].") - return - else if(istype(I, refill_canister) && refill_canister != null) - if(stat & (BROKEN|NOPOWER)) - to_chat(user, "It does nothing.") - else if(panel_open) - //if the panel is open we attempt to refill the machine - var/obj/item/vending_refill/canister = I - if(canister.charges[STANDARD_CHARGE] == 0) - to_chat(user, "This [canister.name] is empty!") - else - var/transfered = refill_inventory(canister,product_records,STANDARD_CHARGE) - transfered += refill_inventory(canister,coin_records,COIN_CHARGE) - transfered += refill_inventory(canister,hidden_records,CONTRABAND_CHARGE) - if(transfered) - to_chat(user, "You loaded [transfered] items in \the [name].") - else - to_chat(user, "The [name] is fully stocked.") - return - else - to_chat(user, "You should probably unscrew the service panel first.") - else - return ..() - - -/obj/machinery/vending/on_deconstruction() - var/product_list = list(product_records, hidden_records, coin_records) - for(var/i=1, i<=3, i++) - for(var/datum/data/vending_product/machine_content in product_list[i]) - while(machine_content.amount !=0) - var/safety = 0 //to avoid infinite loop - for(var/obj/item/vending_refill/VR in component_parts) - safety++ - if(VR.charges[i] < VR.init_charges[i]) - VR.charges[i]++ - machine_content.amount-- - if(!machine_content.amount) - break - else - safety-- - if(safety <= 0) // all refill canisters are full - break - ..() - -/obj/machinery/vending/emag_act(mob/user) - if(obj_flags & EMAGGED) - return - obj_flags |= EMAGGED - to_chat(user, "You short out the product lock on [src].") - -/obj/machinery/vending/attack_ai(mob/user) - return attack_hand(user) - -/obj/machinery/vending/attack_hand(mob/user) - var/dat = "" - if(panel_open && !isAI(user)) - return wires.interact(user) - else - if(stat & (BROKEN|NOPOWER)) - return - - dat += "

Select an item

" - dat += "
" - if(product_records.len == 0) - dat += "No product loaded!" - else - var/list/display_records = product_records - if(extended_inventory) - display_records = product_records + hidden_records - if(coin || bill) - display_records = product_records + coin_records - if((coin || bill) && extended_inventory) - display_records = product_records + hidden_records + coin_records - dat += "" - dat += "
" - if(premium.len > 0) - dat += "Change Return: " - if (coin || bill) - dat += "[(coin ? coin : "")][(bill ? bill : "")]  Remove" - else - dat += "No money  Remove" - if(istype(src, /obj/machinery/vending/snack)) - dat += "

Chef's Food Selection

" - dat += "
" - for (var/O in dish_quants) - if(dish_quants[O] > 0) - var/N = dish_quants[O] - dat += "Dispense " - dat += "[capitalize(O)]: [N]
" - dat += "
" - user.set_machine(src) - if(seconds_electrified && !(stat & NOPOWER)) - if(shock(user, 100)) - return - - var/datum/browser/popup = new(user, "vending", (name)) - popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state)) - popup.open() - - -/obj/machinery/vending/Topic(href, href_list) - if(..()) - return - - if(href_list["remove_coin"]) - if(!(coin || bill)) - to_chat(usr, "There is no money in this machine.") - return - if(coin) - if(!usr.get_active_held_item()) - usr.put_in_hands(coin) - else - coin.forceMove(get_turf(src)) - to_chat(usr, "You remove [coin] from [src].") - coin = null - if(bill) - if(!usr.get_active_held_item()) - usr.put_in_hands(bill) - else - bill.forceMove(get_turf(src)) - to_chat(usr, "You remove [bill] from [src].") - bill = null - - - usr.set_machine(src) - - if((href_list["dispense"]) && (vend_ready)) - var/N = href_list["dispense"] - if(dish_quants[N] <= 0) // Sanity check, there are probably ways to press the button when it shouldn't be possible. - return - vend_ready = 0 - use_power(5) - - dish_quants[N] = max(dish_quants[N] - 1, 0) - for(var/obj/O in contents) - if(O.name == N) - O.forceMove(drop_location()) - break - vend_ready = 1 - updateUsrDialog() - return - - if((href_list["vend"]) && (vend_ready)) - if(panel_open) - to_chat(usr, "The vending machine cannot dispense products while its service panel is open!") - return - - if((!allowed(usr)) && !(obj_flags & EMAGGED) && scan_id) //For SECURE VENDING MACHINES YEAH - to_chat(usr, "Access denied." ) - flick(icon_deny,src) - return - - vend_ready = 0 //One thing at a time!! - - var/datum/data/vending_product/R = locate(href_list["vend"]) - if(!R || !istype(R) || !R.product_path) - vend_ready = 1 - return - - if(R in hidden_records) - if(!extended_inventory) - vend_ready = 1 - return - else if(R in coin_records) - if(!(coin || bill)) - to_chat(usr, "You need to insert money to get this item!") - vend_ready = 1 - return - if(coin && coin.string_attached) - if(prob(50)) - if(usr.put_in_hands(coin)) - to_chat(usr, "You successfully pull [coin] out before [src] could swallow it.") - coin = null - else - to_chat(usr, "You couldn't pull [coin] out because your hands are full!") - QDEL_NULL(coin) - else - to_chat(usr, "You weren't able to pull [coin] out fast enough, the machine ate it, string and all!") - QDEL_NULL(coin) - else - QDEL_NULL(coin) - QDEL_NULL(bill) - - else if (!(R in product_records)) - vend_ready = 1 - message_admins("Vending machine exploit attempted by [key_name(usr, usr.client)]!") - return - - if (R.amount <= 0) - to_chat(usr, "Sold out.") - vend_ready = 1 - return - else - R.amount-- - - if(((last_reply + 200) <= world.time) && vend_reply) - speak(vend_reply) - last_reply = world.time - - use_power(5) - if(icon_vend) //Show the vending animation if needed - flick(icon_vend,src) - new R.product_path(get_turf(src)) - SSblackbox.record_feedback("nested tally", "vending_machine_usage", 1, list("[type]", "[R.product_path]")) - vend_ready = 1 - return - - updateUsrDialog() - return - - else if(href_list["togglevoice"] && panel_open) - shut_up = !shut_up - - updateUsrDialog() - - -/obj/machinery/vending/process() - if(stat & (BROKEN|NOPOWER)) - return - if(!active) - return - - if(seconds_electrified > 0) - seconds_electrified-- - - //Pitch to the people! Really sell it! - if(last_slogan + slogan_delay <= world.time && slogan_list.len > 0 && !shut_up && prob(5)) - var/slogan = pick(slogan_list) - speak(slogan) - last_slogan = world.time - - if(shoot_inventory && prob(shoot_inventory_chance)) - throw_item() - - -/obj/machinery/vending/proc/speak(message) - if(stat & (BROKEN|NOPOWER)) - return - if(!message) - return - - say(message) - -/obj/machinery/vending/power_change() - if(stat & BROKEN) - icon_state = "[initial(icon_state)]-broken" - else - if(powered()) - icon_state = initial(icon_state) - stat &= ~NOPOWER - else - icon_state = "[initial(icon_state)]-off" - stat |= NOPOWER - - -//Somebody cut an important wire and now we're following a new definition of "pitch." -/obj/machinery/vending/proc/throw_item() - var/obj/throw_item = null - var/mob/living/target = locate() in view(7,src) - if(!target) - return 0 - - for(var/datum/data/vending_product/R in shuffle(product_records)) - if(R.amount <= 0) //Try to use a record that actually has something to dump. - continue - var/dump_path = R.product_path - if(!dump_path) - continue - - R.amount-- - throw_item = new dump_path(loc) - break - if(!throw_item) - return 0 - - pre_throw(throw_item) - - throw_item.throw_at(target, 16, 3) - visible_message("[src] launches [throw_item] at [target]!") - return 1 - -/obj/machinery/vending/proc/pre_throw(obj/item/I) - return - - -/obj/machinery/vending/proc/shock(mob/user, prb) - if(stat & (BROKEN|NOPOWER)) // unpowered, no shock - return FALSE - if(!prob(prb)) - return FALSE - do_sparks(5, TRUE, src) - var/tmp/check_range = TRUE - if(electrocute_mob(user, get_area(src), src, 0.7, check_range)) - return TRUE - else - return FALSE - -/* - * Vending machine types - */ - -/* - -/obj/machinery/vending/[vendors name here] // --vending machine template :) - name = "" - desc = "" - icon = '' - icon_state = "" - products = list() - contraband = list() - premium = list() - -IF YOU MODIFY THE PRODUCTS LIST OF A MACHINE, MAKE SURE TO UPDATE ITS RESUPPLY CANISTER CHARGES in vending_items.dm -*/ - -/obj/machinery/vending/boozeomat - name = "\improper Booze-O-Mat" - desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one." - icon_state = "boozeomat" //////////////18 drink entities below, plus the glasses, in case someone wants to edit the number of bottles - icon_deny = "boozeomat-deny" - products = list(/obj/item/reagent_containers/food/drinks/bottle/gin = 5, /obj/item/reagent_containers/food/drinks/bottle/whiskey = 5, - /obj/item/reagent_containers/food/drinks/bottle/tequila = 5, /obj/item/reagent_containers/food/drinks/bottle/vodka = 5, - /obj/item/reagent_containers/food/drinks/bottle/vermouth = 5, /obj/item/reagent_containers/food/drinks/bottle/rum = 5, - /obj/item/reagent_containers/food/drinks/bottle/wine = 5, /obj/item/reagent_containers/food/drinks/bottle/cognac = 5, - /obj/item/reagent_containers/food/drinks/bottle/kahlua = 5, /obj/item/reagent_containers/food/drinks/bottle/hcider = 5, - /obj/item/reagent_containers/food/drinks/bottle/absinthe = 5, /obj/item/reagent_containers/food/drinks/bottle/grappa = 5, - /obj/item/reagent_containers/food/drinks/ale = 6, /obj/item/reagent_containers/food/drinks/bottle/orangejuice = 4, - /obj/item/reagent_containers/food/drinks/bottle/tomatojuice = 4, /obj/item/reagent_containers/food/drinks/bottle/limejuice = 4, - /obj/item/reagent_containers/food/drinks/bottle/cream = 4, /obj/item/reagent_containers/food/drinks/soda_cans/tonic = 8, - /obj/item/reagent_containers/food/drinks/soda_cans/cola = 8, /obj/item/reagent_containers/food/drinks/soda_cans/sodawater = 15, - /obj/item/reagent_containers/food/drinks/drinkingglass = 30, /obj/item/reagent_containers/food/drinks/ice = 10, - /obj/item/reagent_containers/food/drinks/drinkingglass/shotglass = 12, /obj/item/reagent_containers/food/drinks/flask = 3, - /obj/item/reagent_containers/food/drinks/beer = 6, /obj/item/reagent_containers/food/drinks/bottle/sake = 5) //CIT CHANGE - Adds Sake to Booze-o-Mat. - contraband = list(/obj/item/reagent_containers/food/drinks/mug/tea = 12) - product_slogans = "I hope nobody asks me for a bloody cup o' tea...;Alcohol is humanity's friend. Would you abandon a friend?;Quite delighted to serve you!;Is nobody thirsty on this station?" - product_ads = "Drink up!;Booze is good for you!;Alcohol is humanity's best friend.;Quite delighted to serve you!;Care for a nice, cold beer?;Nothing cures you like booze!;Have a sip!;Have a drink!;Have a beer!;Beer is good for you!;Only the finest alcohol!;Best quality booze since 2053!;Award-winning wine!;Maximum alcohol!;Man loves beer.;A toast for progress!" - req_access_txt = "25" - refill_canister = /obj/item/vending_refill/boozeomat - -/obj/machinery/vending/assist - products = list( /obj/item/device/assembly/prox_sensor = 5, /obj/item/device/assembly/igniter = 3, /obj/item/device/assembly/signaler = 4, - /obj/item/wirecutters = 1, /obj/item/cartridge/signal = 4) - contraband = list(/obj/item/device/assembly/timer = 2, /obj/item/device/assembly/voice = 2, /obj/item/device/assembly/health = 2) - product_ads = "Only the finest!;Have some tools.;The most robust equipment.;The finest gear in space!" - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/coffee - name = "\improper Solar's Best Hot Drinks" - desc = "A vending machine which dispenses hot drinks." - product_ads = "Have a drink!;Drink up!;It's good for you!;Would you like a hot joe?;I'd kill for some coffee!;The best beans in the galaxy.;Only the finest brew for you.;Mmmm. Nothing like a coffee.;I like coffee, don't you?;Coffee helps you work!;Try some tea.;We hope you like the best!;Try our new chocolate!;Admin conspiracies" - icon_state = "coffee" - icon_vend = "coffee-vend" - products = list(/obj/item/reagent_containers/food/drinks/coffee = 25, /obj/item/reagent_containers/food/drinks/mug/tea = 25, /obj/item/reagent_containers/food/drinks/mug/coco = 25) - contraband = list(/obj/item/reagent_containers/food/drinks/ice = 12) - refill_canister = /obj/item/vending_refill/coffee - -/obj/machinery/vending/snack - name = "\improper Getmore Chocolate Corp" - desc = "A snack machine courtesy of the Getmore Chocolate Corporation, based out of Mars." - product_slogans = "Try our new nougat bar!;Twice the calories for half the price!" - product_ads = "The healthiest!;Award-winning chocolate bars!;Mmm! So good!;Oh my god it's so juicy!;Have a snack.;Snacks are good for you!;Have some more Getmore!;Best quality snacks straight from mars.;We love chocolate!;Try our new jerky!" - icon_state = "snack" - products = list(/obj/item/reagent_containers/food/snacks/candy = 6, /obj/item/reagent_containers/food/drinks/dry_ramen = 6, /obj/item/reagent_containers/food/snacks/chips =6, - /obj/item/reagent_containers/food/snacks/sosjerky = 6, /obj/item/reagent_containers/food/snacks/no_raisin = 6, /obj/item/reagent_containers/food/snacks/spacetwinkie = 6, - /obj/item/reagent_containers/food/snacks/cheesiehonkers = 6) - contraband = list(/obj/item/reagent_containers/food/snacks/syndicake = 6) - refill_canister = /obj/item/vending_refill/snack - var/chef_compartment_access = "28" - -/obj/machinery/vending/snack/random - name = "\improper Random Snackies" - icon_state = "random_snack" - desc = "Uh oh!" - -/obj/machinery/vending/snack/random/Initialize() - ..() - var/T = pick(subtypesof(/obj/machinery/vending/snack) - /obj/machinery/vending/snack/random) - new T(loc) - return INITIALIZE_HINT_QDEL - -/obj/machinery/vending/snack/blue - icon_state = "snackblue" - -/obj/machinery/vending/snack/orange - icon_state = "snackorange" - -/obj/machinery/vending/snack/green - icon_state = "snackgreen" - -/obj/machinery/vending/snack/teal - icon_state = "snackteal" - -/obj/machinery/vending/sustenance - name = "\improper Sustenance Vendor" - desc = "A vending machine which vends food, as required by section 47-C of the NT's Prisoner Ethical Treatment Agreement." - product_slogans = "Enjoy your meal.;Enough calories to support strenuous labor." - product_ads = "Sufficiently healthy.;Efficiently produced tofu!;Mmm! So good!;Have a meal.;You need food to live!;Have some more candy corn!;Try our new ice cups!" - icon_state = "sustenance" - products = list(/obj/item/reagent_containers/food/snacks/tofu = 24, - /obj/item/reagent_containers/food/drinks/ice = 12, - /obj/item/reagent_containers/food/snacks/candy_corn = 6) - contraband = list(/obj/item/kitchen/knife = 6, - /obj/item/reagent_containers/food/drinks/coffee = 12, - /obj/item/tank/internals/emergency_oxygen = 6, - /obj/item/clothing/mask/breath = 6) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/cola - name = "\improper Robust Softdrinks" - desc = "A softdrink vendor provided by Robust Industries, LLC." - icon_state = "Cola_Machine" - product_slogans = "Robust Softdrinks: More robust than a toolbox to the head!" - product_ads = "Refreshing!;Hope you're thirsty!;Over 1 million drinks sold!;Thirsty? Why not cola?;Please, have a drink!;Drink up!;The best drinks in space." - products = list(/obj/item/reagent_containers/food/drinks/soda_cans/cola = 10, /obj/item/reagent_containers/food/drinks/soda_cans/space_mountain_wind = 10, - /obj/item/reagent_containers/food/drinks/soda_cans/dr_gibb = 10, /obj/item/reagent_containers/food/drinks/soda_cans/starkist = 10, - /obj/item/reagent_containers/food/drinks/soda_cans/space_up = 10, /obj/item/reagent_containers/food/drinks/soda_cans/pwr_game = 10, - /obj/item/reagent_containers/food/drinks/soda_cans/lemon_lime = 10, /obj/item/reagent_containers/glass/beaker/waterbottle = 10) - contraband = list(/obj/item/reagent_containers/food/drinks/soda_cans/thirteenloko = 6, /obj/item/reagent_containers/food/drinks/soda_cans/shamblers = 6) - premium = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/nuka_cola = 1, /obj/item/reagent_containers/food/drinks/soda_cans/air = 1) - refill_canister = /obj/item/vending_refill/cola - -/obj/machinery/vending/cola/random - name = "\improper Random Drinkies" - icon_state = "random_cola" - desc = "Uh oh!" - -/obj/machinery/vending/cola/random/Initialize() - ..() - var/T = pick(subtypesof(/obj/machinery/vending/cola) - /obj/machinery/vending/cola/random) - new T(loc) - return INITIALIZE_HINT_QDEL - -/obj/machinery/vending/cola/blue - icon_state = "Cola_Machine" - -/obj/machinery/vending/cola/black - icon_state = "cola_black" - -/obj/machinery/vending/cola/red - icon_state = "red_cola" - name = "\improper Space Cola Vendor" - desc = "It vends cola, in space." - product_slogans = "Cola in space!" - -/obj/machinery/vending/cola/space_up - icon_state = "space_up" - name = "\improper Space-up! Vendor" - desc = "Indulge in an explosion of flavor." - product_slogans = "Space-up! Like a hull breach in your mouth." - -/obj/machinery/vending/cola/starkist - icon_state = "starkist" - name = "\improper Star-kist Vendor" - desc = "The taste of a star in liquid form." - product_slogans = "Drink the stars! Star-kist!" - -/obj/machinery/vending/cola/sodie - icon_state = "soda" - -/obj/machinery/vending/cola/pwr_game - icon_state = "pwr_game" - name = "\improper Pwr Game Vendor" - desc = "You want it, we got it. Brought to you in partnership with Vlad's Salads." - product_slogans = "The POWER that gamers crave! PWR GAME!" - -/obj/machinery/vending/cola/shamblers - name = "\improper Shambler's Vendor" - desc = "~Shake me up some of that Shambler's Juice!~" - icon_state = "shamblers_juice" - products = list(/obj/item/reagent_containers/food/drinks/soda_cans/cola = 10, /obj/item/reagent_containers/food/drinks/soda_cans/space_mountain_wind = 10, - /obj/item/reagent_containers/food/drinks/soda_cans/dr_gibb = 10, /obj/item/reagent_containers/food/drinks/soda_cans/starkist = 10, - /obj/item/reagent_containers/food/drinks/soda_cans/space_up = 10, /obj/item/reagent_containers/food/drinks/soda_cans/pwr_game = 10, - /obj/item/reagent_containers/food/drinks/soda_cans/lemon_lime = 10, /obj/item/reagent_containers/food/drinks/soda_cans/shamblers = 10) - product_slogans = "~Shake me up some of that Shambler's Juice!~" - product_ads = "Refreshing!;Jyrbv dv lg jfdv fw kyrk Jyrdscvi'j Alztv!;Over 1 trillion souls drank!;Thirsty? Nyp efk uizeb kyv uribevjj?;Kyv Jyrdscvi uizebj kyv ezxyk!;Drink up!;Krjkp." - - -//This one's from bay12 -/obj/machinery/vending/cart - name = "\improper PTech" - desc = "Cartridges for PDAs." - product_slogans = "Carts to go!" - icon_state = "cart" - icon_deny = "cart-deny" - products = list(/obj/item/cartridge/medical = 10, /obj/item/cartridge/engineering = 10, /obj/item/cartridge/security = 10, - /obj/item/cartridge/janitor = 10, /obj/item/cartridge/signal/toxins = 10, /obj/item/device/pda/heads = 10, - /obj/item/cartridge/captain = 3, /obj/item/cartridge/quartermaster = 10) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/liberationstation - name = "\improper Liberation Station" - desc = "An overwhelming amount of ancient patriotism washes over you just by looking at the machine." - icon_state = "liberationstation" - req_access_txt = "1" - product_slogans = "Liberation Station: Your one-stop shop for all things second ammendment!;Be a patriot today, pick up a gun!;Quality weapons for cheap prices!;Better dead than red!" - product_ads = "Float like an astronaut, sting like a bullet!;Express your second ammendment today!;Guns don't kill people, but you can!;Who needs responsibilities when you have guns?" - vend_reply = "Remember the name: Liberation Station!" - products = list(/obj/item/gun/ballistic/automatic/pistol/deagle/gold = 2, /obj/item/gun/ballistic/automatic/pistol/deagle/camo = 2, - /obj/item/gun/ballistic/automatic/pistol/m1911 = 2, /obj/item/gun/ballistic/automatic/proto/unrestricted = 2, - /obj/item/gun/ballistic/shotgun/automatic/combat = 2, /obj/item/gun/ballistic/automatic/gyropistol = 1, - /obj/item/gun/ballistic/shotgun = 2, /obj/item/gun/ballistic/automatic/ar = 2) - premium = list(/obj/item/ammo_box/magazine/smgm9mm = 2, /obj/item/ammo_box/magazine/m50 = 4, /obj/item/ammo_box/magazine/m45 = 2, /obj/item/ammo_box/magazine/m75 = 2) - contraband = list(/obj/item/clothing/under/patriotsuit = 1, /obj/item/bedsheet/patriot = 3) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/cigarette - name = "\improper ShadyCigs Deluxe" - desc = "If you want to get cancer, might as well do it in style." - product_slogans = "Space cigs taste good like a cigarette should.;I'd rather toolbox than switch.;Smoke!;Don't believe the reports - smoke today!" - product_ads = "Probably not bad for you!;Don't believe the scientists!;It's good for you!;Don't quit, buy more!;Smoke!;Nicotine heaven.;Best cigarettes since 2150.;Award-winning cigs." - icon_state = "cigs" - products = list(/obj/item/storage/fancy/cigarettes = 5, - /obj/item/storage/fancy/cigarettes/cigpack_uplift = 3, - /obj/item/storage/fancy/cigarettes/cigpack_robust = 3, - /obj/item/storage/fancy/cigarettes/cigpack_carp = 3, - /obj/item/storage/fancy/cigarettes/cigpack_midori = 3, - /obj/item/storage/box/matches = 10, - /obj/item/lighter/greyscale = 4, - /obj/item/storage/fancy/rollingpapers = 5) - contraband = list(/obj/item/lighter = 3, /obj/item/clothing/mask/vape = 5) - premium = list(/obj/item/storage/fancy/cigarettes/cigpack_robustgold = 3, \ - /obj/item/storage/fancy/cigarettes/cigars = 1, /obj/item/storage/fancy/cigarettes/cigars/havana = 1, /obj/item/storage/fancy/cigarettes/cigars/cohiba = 1) - refill_canister = /obj/item/vending_refill/cigarette - -/obj/machinery/vending/cigarette/pre_throw(obj/item/I) - if(istype(I, /obj/item/lighter)) - var/obj/item/lighter/L = I - L.set_lit(TRUE) - -/obj/machinery/vending/medical - name = "\improper NanoMed Plus" - desc = "Medical drug dispenser." - icon_state = "med" - icon_deny = "med-deny" - product_ads = "Go save some lives!;The best stuff for your medbay.;Only the finest tools.;Natural chemicals!;This stuff saves lives.;Don't you want some?;Ping!" - req_access_txt = "5" - /* - products = list(/obj/item/reagent_containers/syringe = 12, - /obj/item/reagent_containers/dropper = 3, - /obj/item/device/healthanalyzer = 4, - /obj/item/device/sensor_device = 2, - /obj/item/pinpointer/crew = 2, - /obj/item/reagent_containers/medspray/sterilizine = 1, - /obj/item/stack/medical/gauze = 8, - /obj/item/reagent_containers/pill/patch/styptic = 5, - /obj/item/reagent_containers/medspray/styptic = 2, - /obj/item/reagent_containers/pill/patch/silver_sulf = 5, - /obj/item/reagent_containers/medspray/silver_sulf = 2, - /obj/item/reagent_containers/pill/insulin = 10, - /obj/item/reagent_containers/pill/salbutamol = 2, - /obj/item/reagent_containers/glass/bottle/charcoal = 4, - /obj/item/reagent_containers/glass/bottle/epinephrine = 4, - /obj/item/reagent_containers/glass/bottle/salglu_solution = 3, - /obj/item/reagent_containers/glass/bottle/morphine = 4, - /obj/item/reagent_containers/glass/bottle/toxin = 3, - /obj/item/reagent_containers/syringe/antiviral = 6) - */ //products list in modular_citadel's version of this file - contraband = list(/obj/item/reagent_containers/pill/tox = 3, /obj/item/reagent_containers/pill/morphine = 4, /obj/item/reagent_containers/pill/charcoal = 6) - premium = list(/obj/item/storage/box/hug/medical = 1, /obj/item/reagent_containers/hypospray/medipen = 3, /obj/item/storage/belt/medical = 3, /obj/item/wrench/medical = 1) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - refill_canister = /obj/item/vending_refill/medical - -//This one's from bay12 -/obj/machinery/vending/plasmaresearch - name = "\improper Toximate 3000" - desc = "All the fine parts you need in one vending machine!" - products = list(/obj/item/clothing/under/rank/scientist = 6, /obj/item/clothing/suit/bio_suit = 6, /obj/item/clothing/head/bio_hood = 6, - /obj/item/device/transfer_valve = 6, /obj/item/device/assembly/timer = 6, /obj/item/device/assembly/signaler = 6, - /obj/item/device/assembly/prox_sensor = 6, /obj/item/device/assembly/igniter = 6) - contraband = list(/obj/item/device/assembly/health = 3) - -/obj/machinery/vending/wallmed - name = "\improper NanoMed" - desc = "Wall-mounted Medical Equipment dispenser." - icon_state = "wallmed" - icon_deny = "wallmed-deny" - density = FALSE - products = list(/obj/item/reagent_containers/syringe = 3, /obj/item/reagent_containers/pill/patch/styptic = 5, - /obj/item/reagent_containers/pill/patch/silver_sulf = 5, /obj/item/reagent_containers/medspray/styptic = 2, /obj/item/reagent_containers/medspray/silver_sulf = 2, - /obj/item/reagent_containers/pill/charcoal = 2, /obj/item/reagent_containers/medspray/sterilizine = 1) - contraband = list(/obj/item/reagent_containers/pill/tox = 2, /obj/item/reagent_containers/pill/morphine = 2) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - refill_canister = /obj/item/vending_refill/medical - refill_count = 1 - -/obj/machinery/vending/security - name = "\improper SecTech" - desc = "A security equipment vendor." - product_ads = "Crack capitalist skulls!;Beat some heads in!;Don't forget - harm is good!;Your weapons are right here.;Handcuffs!;Freeze, scumbag!;Don't tase me bro!;Tase them, bro.;Why not have a donut?" - icon_state = "sec" - icon_deny = "sec-deny" - req_access_txt = "1" - products = list(/obj/item/restraints/handcuffs = 8, /obj/item/restraints/handcuffs/cable/zipties = 10, /obj/item/grenade/flashbang = 4, /obj/item/device/assembly/flash/handheld = 5, - /obj/item/reagent_containers/food/snacks/donut = 12, /obj/item/storage/box/evidence = 6, /obj/item/device/flashlight/seclite = 4, /obj/item/restraints/legcuffs/bola/energy = 7) - contraband = list(/obj/item/clothing/glasses/sunglasses = 2, /obj/item/storage/fancy/donut_box = 2) - premium = list(/obj/item/coin/antagtoken = 1) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/security/pre_throw(obj/item/I) - if(istype(I, /obj/item/grenade)) - var/obj/item/grenade/G = I - G.preprime() - else if(istype(I, /obj/item/device/flashlight)) - var/obj/item/device/flashlight/F = I - F.on = TRUE - F.update_brightness() - -/obj/machinery/vending/hydronutrients - name = "\improper NutriMax" - desc = "A plant nutrients vendor." - product_slogans = "Aren't you glad you don't have to fertilize the natural way?;Now with 50% less stink!;Plants are people too!" - product_ads = "We like plants!;Don't you want some?;The greenest thumbs ever.;We like big plants.;Soft soil..." - icon_state = "nutri" - icon_deny = "nutri-deny" - products = list(/obj/item/reagent_containers/glass/bottle/nutrient/ez = 30, /obj/item/reagent_containers/glass/bottle/nutrient/l4z = 20, /obj/item/reagent_containers/glass/bottle/nutrient/rh = 10, /obj/item/reagent_containers/spray/pestspray = 20, - /obj/item/reagent_containers/syringe = 5, /obj/item/storage/bag/plants = 5, /obj/item/cultivator = 3, /obj/item/shovel/spade = 3, /obj/item/device/plant_analyzer = 4) - contraband = list(/obj/item/reagent_containers/glass/bottle/ammonia = 10, /obj/item/reagent_containers/glass/bottle/diethylamine = 5) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/hydroseeds - name = "\improper MegaSeed Servitor" - desc = "When you need seeds fast!" - product_slogans = "THIS'S WHERE TH' SEEDS LIVE! GIT YOU SOME!;Hands down the best seed selection on the station!;Also certain mushroom varieties available, more for experts! Get certified today!" - product_ads = "We like plants!;Grow some crops!;Grow, baby, growww!;Aw h'yeah son!" - icon_state = "seeds" - products = list(/obj/item/seeds/ambrosia = 3, /obj/item/seeds/apple = 3, /obj/item/seeds/banana = 3, /obj/item/seeds/berry = 3, - /obj/item/seeds/cabbage = 3, /obj/item/seeds/carrot = 3, /obj/item/seeds/cherry = 3, /obj/item/seeds/chanter = 3, - /obj/item/seeds/chili = 3, /obj/item/seeds/cocoapod = 3, /obj/item/seeds/coffee = 3, /obj/item/seeds/corn = 3, - /obj/item/seeds/eggplant = 3, /obj/item/seeds/grape = 3, /obj/item/seeds/grass = 3, /obj/item/seeds/lemon = 3, - /obj/item/seeds/lime = 3, /obj/item/seeds/onion = 3, /obj/item/seeds/orange = 3, /obj/item/seeds/pineapple = 3, /obj/item/seeds/potato = 3, - /obj/item/seeds/poppy = 3,/obj/item/seeds/pumpkin = 3, /obj/item/seeds/replicapod = 3, /obj/item/seeds/wheat/rice = 3, /obj/item/seeds/soya = 3, - /obj/item/seeds/sunflower = 3, /obj/item/seeds/tea = 3, /obj/item/seeds/tobacco = 3, /obj/item/seeds/tomato = 3, - /obj/item/seeds/tower = 3, /obj/item/seeds/watermelon = 3, /obj/item/seeds/wheat = 3, /obj/item/seeds/whitebeet = 3) - contraband = list(/obj/item/seeds/amanita = 2, /obj/item/seeds/glowshroom = 2, /obj/item/seeds/liberty = 2, /obj/item/seeds/nettle = 2, - /obj/item/seeds/plump = 2, /obj/item/seeds/reishi = 2, /obj/item/seeds/cannabis = 3, /obj/item/seeds/starthistle = 2, - /obj/item/seeds/random = 2) - premium = list(/obj/item/reagent_containers/spray/waterflower = 1) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/magivend - name = "\improper MagiVend" - desc = "A magic vending machine." - icon_state = "MagiVend" - product_slogans = "Sling spells the proper way with MagiVend!;Be your own Houdini! Use MagiVend!" - vend_reply = "Have an enchanted evening!" - product_ads = "FJKLFJSD;AJKFLBJAKL;1234 LOONIES LOL!;>MFW;Kill them fuckers!;GET DAT FUKKEN DISK;HONK!;EI NATH;Destroy the station!;Admin conspiracies since forever!;Space-time bending hardware!" - products = list(/obj/item/clothing/head/wizard = 1, /obj/item/clothing/suit/wizrobe = 1, /obj/item/clothing/head/wizard/red = 1, /obj/item/clothing/suit/wizrobe/red = 1, /obj/item/clothing/head/wizard/yellow = 1, /obj/item/clothing/suit/wizrobe/yellow = 1, /obj/item/clothing/shoes/sandal/magic = 1, /obj/item/staff = 2) - contraband = list(/obj/item/reagent_containers/glass/bottle/wizarditis = 1) //No one can get to the machine to hack it anyways; for the lulz - Microwave - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/autodrobe - name = "\improper AutoDrobe" - desc = "A vending machine for costumes." - icon_state = "theater" - icon_deny = "theater-deny" - req_access_txt = "46" //Theatre access needed, unless hacked. - product_slogans = "Dress for success!;Suited and booted!;It's show time!;Why leave style up to fate? Use AutoDrobe!" - vend_reply = "Thank you for using AutoDrobe!" - products = list(/obj/item/clothing/suit/chickensuit = 1, /obj/item/clothing/head/chicken = 1, /obj/item/clothing/under/gladiator = 1, - /obj/item/clothing/head/helmet/gladiator = 1, /obj/item/clothing/under/gimmick/rank/captain/suit = 1, /obj/item/clothing/head/flatcap = 1, - /obj/item/clothing/suit/toggle/labcoat/mad = 1, /obj/item/clothing/shoes/jackboots = 1, - /obj/item/clothing/under/schoolgirl = 1, /obj/item/clothing/under/schoolgirl/red = 1, /obj/item/clothing/under/schoolgirl/green = 1, /obj/item/clothing/under/schoolgirl/orange = 1, /obj/item/clothing/head/kitty = 1, /obj/item/clothing/under/skirt/black = 1, /obj/item/clothing/head/beret = 1, - /obj/item/clothing/accessory/waistcoat = 1, /obj/item/clothing/under/suit_jacket = 1, /obj/item/clothing/head/that =1, /obj/item/clothing/under/kilt = 1, /obj/item/clothing/head/beret = 1, /obj/item/clothing/accessory/waistcoat = 1, - /obj/item/clothing/glasses/monocle =1, /obj/item/clothing/head/bowler = 1, /obj/item/cane = 1, /obj/item/clothing/under/sl_suit = 1, - /obj/item/clothing/mask/fakemoustache = 1, /obj/item/clothing/suit/bio_suit/plaguedoctorsuit = 1, /obj/item/clothing/head/plaguedoctorhat = 1, /obj/item/clothing/mask/gas/plaguedoctor = 1, - /obj/item/clothing/suit/toggle/owlwings = 1, /obj/item/clothing/under/owl = 1, /obj/item/clothing/mask/gas/owl_mask = 1, - /obj/item/clothing/suit/toggle/owlwings/griffinwings = 1, /obj/item/clothing/under/griffin = 1, /obj/item/clothing/shoes/griffin = 1, /obj/item/clothing/head/griffin = 1, - /obj/item/clothing/suit/apron = 1, /obj/item/clothing/under/waiter = 1, /obj/item/clothing/suit/jacket/miljacket = 1, - /obj/item/clothing/under/pirate = 1, /obj/item/clothing/suit/pirate = 1, /obj/item/clothing/head/pirate = 1, /obj/item/clothing/head/bandana = 1, - /obj/item/clothing/head/bandana = 1, /obj/item/clothing/under/soviet = 1, /obj/item/clothing/head/ushanka = 1, /obj/item/clothing/suit/imperium_monk = 1, - /obj/item/clothing/mask/gas/cyborg = 1, /obj/item/clothing/suit/holidaypriest = 1, /obj/item/clothing/head/wizard/marisa/fake = 1, - /obj/item/clothing/suit/wizrobe/marisa/fake = 1, /obj/item/clothing/under/sundress = 1, /obj/item/clothing/head/witchwig = 1, /obj/item/staff/broom = 1, - /obj/item/clothing/suit/wizrobe/fake = 1, /obj/item/clothing/head/wizard/fake = 1, /obj/item/staff = 3, /obj/item/clothing/mask/gas/sexyclown = 1, - /obj/item/clothing/under/rank/clown/sexy = 1, /obj/item/clothing/mask/gas/sexymime = 1, /obj/item/clothing/under/sexymime = 1, /obj/item/clothing/mask/rat/bat = 1, /obj/item/clothing/mask/rat/bee = 1, /obj/item/clothing/mask/rat/bear = 1, /obj/item/clothing/mask/rat/raven = 1, /obj/item/clothing/mask/rat/jackal = 1, /obj/item/clothing/mask/rat/fox = 1, /obj/item/clothing/mask/frog = 1, /obj/item/clothing/mask/rat/tribal = 1, /obj/item/clothing/mask/rat = 1, - /obj/item/clothing/suit/apron/overalls = 1, /obj/item/clothing/head/rabbitears =1, /obj/item/clothing/head/sombrero = 1, /obj/item/clothing/head/sombrero/green = 1, /obj/item/clothing/suit/poncho = 1, - /obj/item/clothing/suit/poncho/green = 1, /obj/item/clothing/suit/poncho/red = 1, - /obj/item/clothing/under/maid = 1, /obj/item/clothing/under/janimaid = 1, /obj/item/clothing/glasses/cold=1, /obj/item/clothing/glasses/heat=1, - /obj/item/clothing/suit/whitedress = 1, - /obj/item/clothing/under/jester = 1, /obj/item/clothing/head/jester = 1, - /obj/item/clothing/under/villain = 1, - /obj/item/clothing/shoes/singery = 1, /obj/item/clothing/under/singery = 1, - /obj/item/clothing/shoes/singerb = 1, /obj/item/clothing/under/singerb = 1, - /obj/item/clothing/suit/hooded/carp_costume = 1, - /obj/item/clothing/suit/hooded/ian_costume = 1, - /obj/item/clothing/suit/hooded/bee_costume = 1, - /obj/item/clothing/suit/snowman = 1, - /obj/item/clothing/head/snowman = 1, - /obj/item/clothing/mask/joy = 1, - /obj/item/clothing/head/cueball = 1, - /obj/item/clothing/under/scratch = 1, - /obj/item/clothing/under/sailor = 1, - /obj/item/clothing/ears/headphones = 2, - /obj/item/clothing/head/wig/random = 3) - contraband = list(/obj/item/clothing/suit/judgerobe = 1, /obj/item/clothing/head/powdered_wig = 1, /obj/item/gun/magic/wand = 2, /obj/item/clothing/glasses/sunglasses/garb = 2, /obj/item/clothing/glasses/sunglasses/blindfold = 1, /obj/item/clothing/mask/muzzle = 2) - premium = list(/obj/item/clothing/suit/pirate/captain = 2, /obj/item/clothing/head/pirate/captain = 2, /obj/item/clothing/head/helmet/roman = 1, /obj/item/clothing/head/helmet/roman/legionaire = 1, /obj/item/clothing/under/roman = 1, /obj/item/clothing/shoes/roman = 1, /obj/item/shield/riot/roman = 1, /obj/item/skub = 1) - refill_canister = /obj/item/vending_refill/autodrobe - -/obj/machinery/vending/dinnerware - name = "\improper Plasteel Chef's Dinnerware Vendor" - desc = "A kitchen and restaurant equipment vendor." - product_ads = "Mm, food stuffs!;Food and food accessories.;Get your plates!;You like forks?;I like forks.;Woo, utensils.;You don't really need these..." - icon_state = "dinnerware" - products = list(/obj/item/storage/bag/tray = 8, /obj/item/kitchen/fork = 6, /obj/item/kitchen/knife = 6, /obj/item/kitchen/rollingpin = 2, /obj/item/reagent_containers/food/drinks/drinkingglass = 8, /obj/item/clothing/suit/apron/chef = 2, /obj/item/reagent_containers/food/condiment/pack/ketchup = 5, /obj/item/reagent_containers/food/condiment/pack/hotsauce = 5, /obj/item/reagent_containers/food/condiment/saltshaker = 5, /obj/item/reagent_containers/food/condiment/peppermill = 5, /obj/item/reagent_containers/glass/bowl = 20) - contraband = list(/obj/item/kitchen/rollingpin = 2, /obj/item/kitchen/knife/butcher = 2) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/sovietsoda - name = "\improper BODA" - desc = "Old sweet water vending machine." - icon_state = "sovietsoda" - product_ads = "For Tsar and Country.;Have you fulfilled your nutrition quota today?;Very nice!;We are simple people, for this is all we eat.;If there is a person, there is a problem. If there is no person, then there is no problem." - products = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/soda = 30) - contraband = list(/obj/item/reagent_containers/food/drinks/drinkingglass/filled/cola = 20) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/tool - name = "\improper YouTool" - desc = "Tools for tools." - icon_state = "tool" - icon_deny = "tool-deny" - //req_access_txt = "12" //Maintenance access - products = list( - /obj/item/stack/cable_coil/random = 10, - /obj/item/crowbar = 5, - /obj/item/weldingtool = 3, - /obj/item/wirecutters = 5, - /obj/item/wrench = 5, - /obj/item/device/analyzer = 5, - /obj/item/device/t_scanner = 5, - /obj/item/screwdriver = 5, - /obj/item/device/flashlight/glowstick = 3, - /obj/item/device/flashlight/glowstick/red = 3, - /obj/item/device/flashlight = 5) - contraband = list( - /obj/item/weldingtool/hugetank = 2, - /obj/item/clothing/gloves/color/fyellow = 2) - premium = list( - /obj/item/clothing/gloves/color/yellow = 1) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 70) - resistance_flags = FIRE_PROOF - -/obj/machinery/vending/engivend - name = "\improper Engi-Vend" - desc = "Spare tool vending. What? Did you expect some witty description?" - icon_state = "engivend" - icon_deny = "engivend-deny" - req_access_txt = "11" //Engineering Equipment access - products = list(/obj/item/clothing/glasses/meson/engine = 2, - /obj/item/clothing/glasses/welding = 3, - /obj/item/device/multitool = 4, - /obj/item/construction/rcd/loaded = 3, - /obj/item/grenade/chem_grenade/smart_metal_foam = 10, - /obj/item/device/geiger_counter = 5, - /obj/item/stock_parts/cell/high = 10, - /obj/item/electronics/airlock = 10, - /obj/item/electronics/apc = 10, - /obj/item/electronics/airalarm = 10) - contraband = list(/obj/item/stock_parts/cell/potato = 3) - premium = list(/obj/item/storage/belt/utility = 3, /obj/item/storage/box/smart_metal_foam = 1) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -//This one's from bay12 -/obj/machinery/vending/engineering - name = "\improper Robco Tool Maker" - desc = "Everything you need for do-it-yourself station repair." - icon_state = "engi" - icon_deny = "engi-deny" - req_access_txt = "11" - products = list(/obj/item/clothing/under/rank/chief_engineer = 4, /obj/item/clothing/under/rank/engineer = 4, /obj/item/clothing/shoes/sneakers/orange = 4, /obj/item/clothing/head/hardhat = 4, - /obj/item/storage/belt/utility = 4, /obj/item/clothing/glasses/meson/engine = 4, /obj/item/clothing/gloves/color/yellow = 4, /obj/item/screwdriver = 12, - /obj/item/crowbar = 12, /obj/item/wirecutters = 12, /obj/item/device/multitool = 12, /obj/item/wrench = 12, /obj/item/device/t_scanner = 12, - /obj/item/stock_parts/cell = 8, /obj/item/weldingtool = 8, /obj/item/clothing/head/welding = 8, - /obj/item/light/tube = 10, /obj/item/clothing/suit/fire = 4, /obj/item/stock_parts/scanning_module = 5, /obj/item/stock_parts/micro_laser = 5, - /obj/item/stock_parts/matter_bin = 5, /obj/item/stock_parts/manipulator = 5) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -//This one's from bay12 -/obj/machinery/vending/robotics - name = "\improper Robotech Deluxe" - desc = "All the tools you need to create your own robot army." - icon_state = "robotics" - icon_deny = "robotics-deny" - req_access_txt = "29" - products = list(/obj/item/clothing/suit/toggle/labcoat = 4, /obj/item/clothing/under/rank/roboticist = 4, /obj/item/stack/cable_coil = 4, /obj/item/device/assembly/flash/handheld = 4, - /obj/item/stock_parts/cell/high = 12, /obj/item/device/assembly/prox_sensor = 3, /obj/item/device/assembly/signaler = 3, /obj/item/device/healthanalyzer = 3, - /obj/item/scalpel = 2, /obj/item/circular_saw = 2, /obj/item/tank/internals/anesthetic = 2, /obj/item/clothing/mask/breath/medical = 5, - /obj/item/screwdriver = 5, /obj/item/crowbar = 5) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - -//DON'T FORGET TO CHANGE THE REFILL SIZE IF YOU CHANGE THE MACHINE'S CONTENTS! -/obj/machinery/vending/clothing - name = "ClothesMate" //renamed to make the slogan rhyme - desc = "A vending machine for clothing." - icon_state = "clothes" - product_slogans = "Dress for success!;Prepare to look swagalicious!;Look at all this free swag!;Why leave style up to fate? Use the ClothesMate!" - vend_reply = "Thank you for using the ClothesMate!" - products = list(/obj/item/clothing/head/that=2, /obj/item/clothing/head/fedora=1, /obj/item/clothing/glasses/monocle=1, - /obj/item/clothing/suit/jacket=2, /obj/item/clothing/suit/jacket/puffer/vest=2, /obj/item/clothing/suit/jacket/puffer=2, - /obj/item/clothing/under/suit_jacket/navy=1, /obj/item/clothing/under/suit_jacket/really_black=1, /obj/item/clothing/under/suit_jacket/burgundy=1, - /obj/item/clothing/under/suit_jacket/charcoal=1, /obj/item/clothing/under/suit_jacket/white=1, /obj/item/clothing/under/kilt=1, /obj/item/clothing/under/overalls=1, - /obj/item/clothing/under/sl_suit=1, /obj/item/clothing/under/pants/jeans=3, /obj/item/clothing/under/pants/classicjeans=2, - /obj/item/clothing/under/pants/camo = 1, /obj/item/clothing/under/pants/blackjeans=2, /obj/item/clothing/under/pants/khaki=2, - /obj/item/clothing/under/pants/white=2, /obj/item/clothing/under/pants/red=1, /obj/item/clothing/under/pants/black=2, - /obj/item/clothing/under/pants/tan=2, /obj/item/clothing/under/pants/track=1, /obj/item/clothing/suit/jacket/miljacket = 1, - /obj/item/clothing/neck/tie/blue=1, /obj/item/clothing/neck/tie/red=1, /obj/item/clothing/neck/tie/black=1, /obj/item/clothing/neck/tie/horrible=1, - /obj/item/clothing/neck/scarf/red=1, /obj/item/clothing/neck/scarf/green=1, /obj/item/clothing/neck/scarf/darkblue=1, - /obj/item/clothing/neck/scarf/purple=1, /obj/item/clothing/neck/scarf/yellow=1, /obj/item/clothing/neck/scarf/orange=1, - /obj/item/clothing/neck/scarf/cyan=1, /obj/item/clothing/neck/scarf=1, /obj/item/clothing/neck/scarf/black=1, - /obj/item/clothing/neck/scarf/zebra=1, /obj/item/clothing/neck/scarf/christmas=1, /obj/item/clothing/neck/stripedredscarf=1, - /obj/item/clothing/neck/stripedbluescarf=1, /obj/item/clothing/neck/stripedgreenscarf=1, /obj/item/clothing/accessory/waistcoat=1, - /obj/item/clothing/under/skirt/black=1, /obj/item/clothing/under/skirt/blue=1, /obj/item/clothing/under/skirt/red=1, /obj/item/clothing/under/skirt/purple=1, - /obj/item/clothing/under/sundress=2, /obj/item/clothing/under/stripeddress=1, /obj/item/clothing/under/sailordress=1, /obj/item/clothing/under/redeveninggown=1, /obj/item/clothing/under/blacktango=1, - /obj/item/clothing/under/plaid_skirt=1, /obj/item/clothing/under/plaid_skirt/blue=1, /obj/item/clothing/under/plaid_skirt/purple=1, /obj/item/clothing/under/plaid_skirt/green=1, - /obj/item/clothing/glasses/regular=1, /obj/item/clothing/glasses/regular/jamjar=1, /obj/item/clothing/head/sombrero=1, /obj/item/clothing/suit/poncho=1, - /obj/item/clothing/suit/ianshirt=1, /obj/item/clothing/shoes/laceup=2, /obj/item/clothing/shoes/sneakers/black=4, - /obj/item/clothing/shoes/sandal=1, /obj/item/clothing/gloves/fingerless=2, /obj/item/clothing/glasses/orange=1, /obj/item/clothing/glasses/red=1, - /obj/item/storage/belt/fannypack=1, /obj/item/storage/belt/fannypack/blue=1, /obj/item/storage/belt/fannypack/red=1, /obj/item/clothing/suit/jacket/letterman=2, - /obj/item/clothing/head/beanie=1, /obj/item/clothing/head/beanie/black=1, /obj/item/clothing/head/beanie/red=1, /obj/item/clothing/head/beanie/green=1, /obj/item/clothing/head/beanie/darkblue=1, - /obj/item/clothing/head/beanie/purple=1, /obj/item/clothing/head/beanie/yellow=1, /obj/item/clothing/head/beanie/orange=1, /obj/item/clothing/head/beanie/cyan=1, /obj/item/clothing/head/beanie/christmas=1, - /obj/item/clothing/head/beanie/striped=1, /obj/item/clothing/head/beanie/stripedred=1, /obj/item/clothing/head/beanie/stripedblue=1, /obj/item/clothing/head/beanie/stripedgreen=1, - /obj/item/clothing/suit/jacket/letterman_red=1, - /obj/item/clothing/ears/headphones = 10, /obj/item/clothing/suit/apron/purple_bartender=2, /obj/item/clothing/under/rank/bartender/purple=2) - contraband = list(/obj/item/clothing/under/syndicate/tacticool=1, /obj/item/clothing/mask/balaclava=1, /obj/item/clothing/head/ushanka=1, /obj/item/clothing/under/soviet=1, /obj/item/storage/belt/fannypack/black=2, /obj/item/clothing/suit/jacket/letterman_syndie=1, /obj/item/clothing/under/jabroni=1, /obj/item/clothing/suit/vapeshirt=1, /obj/item/clothing/under/geisha=1) - premium = list(/obj/item/clothing/under/suit_jacket/checkered=1, /obj/item/clothing/head/mailman=1, /obj/item/clothing/under/rank/mailman=1, /obj/item/clothing/suit/jacket/leather=1, /obj/item/clothing/suit/jacket/leather/overcoat=1, /obj/item/clothing/under/pants/mustangjeans=1, /obj/item/clothing/neck/necklace/dope=3, /obj/item/clothing/suit/jacket/letterman_nanotrasen=1) - refill_canister = /obj/item/vending_refill/clothing - -/obj/machinery/vending/toyliberationstation - name = "\improper Syndicate Donksoft Toy Vendor" - desc = "An ages 8 and up approved vendor that dispenses toys. If you were to find the right wires, you can unlock the adult mode setting!" - icon_state = "syndi" - req_access_txt = "1" - product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!" - product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!" - vend_reply = "Come back for more!" - products = list(/obj/item/gun/ballistic/automatic/toy/unrestricted = 10, - /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = 10, - /obj/item/gun/ballistic/shotgun/toy/unrestricted = 10, - /obj/item/toy/sword = 10, - /obj/item/ammo_box/foambox = 20, - /obj/item/toy/foamblade = 10, - /obj/item/toy/syndicateballoon = 10, - /obj/item/clothing/suit/syndicatefake = 5, - /obj/item/clothing/head/syndicatefake = 5) //OPS IN DORMS oh wait it's just an assistant - contraband = list(/obj/item/gun/ballistic/shotgun/toy/crossbow = 10, //Congrats, you unlocked the +18 setting! - /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted/riot = 10, - /obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted/riot = 10, - /obj/item/ammo_box/foambox/riot = 20, - /obj/item/toy/katana = 10, - /obj/item/twohanded/dualsaber/toy = 5, - /obj/item/toy/cards/deck/syndicate = 10) //Gambling and it hurts, making it a +18 item - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - refill_canister = /obj/item/vending_refill/donksoft - -/obj/machinery/vending/donksofttoyvendor - name = "\improper Donksoft Toy Vendor" - desc = "Ages 8 and up approved vendor that dispenses toys." - icon_state = "syndi" - product_slogans = "Get your cool toys today!;Trigger a valid hunter today!;Quality toy weapons for cheap prices!;Give them to HoPs for all access!;Give them to HoS to get perma briged!" - product_ads = "Feel robust with your toys!;Express your inner child today!;Toy weapons don't kill people, but valid hunters do!;Who needs responsibilities when you have toy weapons?;Make your next murder FUN!" - vend_reply = "Come back for more!" - products = list(/obj/item/gun/ballistic/automatic/toy/unrestricted = 10, - /obj/item/gun/ballistic/automatic/toy/pistol/unrestricted = 10, - /obj/item/gun/ballistic/shotgun/toy/unrestricted = 10, - /obj/item/toy/sword = 10, - /obj/item/ammo_box/foambox = 20, - /obj/item/toy/foamblade = 10, - /obj/item/toy/syndicateballoon = 10, - /obj/item/clothing/suit/syndicatefake = 5, - /obj/item/clothing/head/syndicatefake = 5) - contraband = list(/obj/item/gun/ballistic/shotgun/toy/crossbow = 10, - /obj/item/gun/ballistic/automatic/c20r/toy/unrestricted = 10, - /obj/item/gun/ballistic/automatic/l6_saw/toy/unrestricted = 10, - /obj/item/toy/katana = 10, - /obj/item/twohanded/dualsaber/toy = 5) - armor = list("melee" = 100, "bullet" = 100, "laser" = 100, "energy" = 100, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 50) - resistance_flags = FIRE_PROOF - refill_canister = /obj/item/vending_refill/donksoft - -/obj/machinery/vending/games - name = "\improper Good Clean Fun" - desc = "Vends things that the Captain and Head of Personnel are probably not going to appreciate you fiddling with instead of your job..." - product_ads = "Escape to a fantasy world!;Fuel your gambling addiction!;Ruin your friendships!;Roll for initative!;Elves and dwarves!;Paranoid computers!;Totally not satanic!;Fun times forever!" - icon_state = "games" - products = list( - /obj/item/toy/cards/deck = 5, - /obj/item/storage/pill_bottle/dice = 10, - /obj/item/toy/cards/deck/cas = 3, - /obj/item/toy/cards/deck/cas/black = 3) - contraband = list(/obj/item/dice/fudge = 9) - refill_canister = /obj/item/vending_refill/games - - -/obj/machinery/vending/onTransitZ() - return - -#undef STANDARD_CHARGE -#undef CONTRABAND_CHARGE -#undef COIN_CHARGE diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 8c371ada2f..78ee151581 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -1,8 +1,8 @@ -#define MECHA_INT_FIRE 1 -#define MECHA_INT_TEMP_CONTROL 2 -#define MECHA_INT_SHORT_CIRCUIT 4 -#define MECHA_INT_TANK_BREACH 8 -#define MECHA_INT_CONTROL_LOST 16 +#define MECHA_INT_FIRE (1<<0) +#define MECHA_INT_TEMP_CONTROL (1<<1) +#define MECHA_INT_SHORT_CIRCUIT (1<<2) +#define MECHA_INT_TANK_BREACH (1<<3) +#define MECHA_INT_CONTROL_LOST (1<<4) #define MELEE 1 #define RANGED 2 diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm index 2ed2105db3..d62146be5e 100644 --- a/code/game/objects/effects/countdown.dm +++ b/code/game/objects/effects/countdown.dm @@ -116,7 +116,7 @@ color = "#00ff80" /obj/effect/countdown/supermatter/get_value() - var/obj/machinery/power/supermatter_shard/S = attached_to + var/obj/machinery/power/supermatter_crystal/S = attached_to if(!istype(S)) return return "
[round(S.get_integrity(), 1)]%
" diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 50371aebe7..46a6d961d4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -100,7 +100,7 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) var/force_string //string form of an item's force. Edit this var only to set a custom force string var/last_force_string_check = 0 var/tip_timer - + var/icon_override //CIT CHANGE - adds icon_override var. Will be removed with #4322 var/trigger_guard = TRIGGER_GUARD_NONE @@ -281,10 +281,8 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(!(interaction_flags_item & INTERACT_ITEM_ATTACK_HAND_PICKUP)) //See if we're supposed to auto pickup. return - if(istype(loc, /obj/item/storage)) - //If the item is in a storage item, take it out - var/obj/item/storage/S = loc - S.remove_from_storage(src, user.loc) + //If the item is in a storage item, take it out + loc.SendSignal(COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE) if(throwing) throwing.finalize(FALSE) @@ -297,15 +295,16 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(!user.put_in_active_hand(src)) dropped(user) +/obj/item/proc/allow_attack_hand_drop(mob/user) + return TRUE + /obj/item/attack_paw(mob/user) if(!user) return if(anchored) return - if(istype(loc, /obj/item/storage)) - var/obj/item/storage/S = loc - S.remove_from_storage(src, user.loc) + loc.SendSignal(COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE) if(throwing) throwing.finalize(FALSE) @@ -338,63 +337,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) R.activate_module(src) R.hud_used.update_robot_modules_display() -// Due to storage type consolidation this should get used more now. -// I have cleaned it up a little, but it could probably use more. -Sayu -// The lack of ..() is intentional, do not add one -// added one, fuck the police -/obj/item/attackby(obj/item/W, mob/user, params) - if(istype(W, /obj/item/storage)) - var/obj/item/storage/S = W - if(S.use_to_pickup) - if(S.collection_mode) //Mode is set to collect multiple items on a tile and we clicked on a valid one. - if(isturf(loc)) - var/list/rejections = list() - - var/list/things = loc.contents.Copy() - if (S.collection_mode == 2) - things = typecache_filter_list(things, typecacheof(type)) - - var/len = things.len - if(!len) - to_chat(user, "You failed to pick up anything with [S].") - return - var/datum/progressbar/progress = new(user, len, loc) - - while (do_after(user, 10, TRUE, S, FALSE, CALLBACK(src, .proc/handle_mass_pickup, S, things, loc, rejections, progress))) - stoplag(1) - - qdel(progress) - - to_chat(user, "You put everything you could [S.preposition] [S].") - return - - else if(S.can_be_inserted(src)) - S.handle_item_insertion(src) - return - return ..() - -/obj/item/proc/handle_mass_pickup(obj/item/storage/S, list/things, atom/thing_loc, list/rejections, datum/progressbar/progress) - for(var/obj/item/I in things) - things -= I - if(I.loc != thing_loc) - continue - if(I.type in rejections) // To limit bag spamming: any given type only complains once - continue - if(!S.can_be_inserted(I, stop_messages = TRUE)) // Note can_be_inserted still makes noise when the answer is no - if(S.contents.len >= S.storage_slots) - break - rejections += I.type // therefore full bags are still a little spammy - continue - - S.handle_item_insertion(I, TRUE) //The 1 stops the "You put the [src] into [S]" insertion message from being displayed. - - if (TICK_CHECK) - progress.update(progress.goal - things.len) - return TRUE - - progress.update(progress.goal - things.len) - return FALSE - /obj/item/proc/GetDeconstructableContents() return GetAllContents() - src @@ -424,17 +366,6 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) SendSignal(COMSIG_ITEM_PICKUP, user) item_flags |= IN_INVENTORY -/obj/item/proc/allow_attack_hand_drop(mob/user) - return TRUE - -// called when this item is removed from a storage item, which is passed on as S. The loc variable is already set to the new destination before this is called. -/obj/item/proc/on_exit_storage(obj/item/storage/S) - return - -// called when this item is added into a storage item, which is passed on as S. The loc variable is already set to the storage item. -/obj/item/proc/on_enter_storage(obj/item/storage/S) - return - // called when "found" in pockets and storage items. Returns 1 if the search should end. /obj/item/proc/on_found(mob/finder) return @@ -518,17 +449,17 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) if(isbrain(M)) to_chat(user, "You cannot locate any organic eyes on this brain!") return - + if(user.getStaminaLoss() >= STAMINA_SOFTCRIT)//CIT CHANGE - makes eyestabbing impossible if you're in stamina softcrit to_chat(user, "You're too exhausted for that.")//CIT CHANGE - ditto return //CIT CHANGE - ditto - + src.add_fingerprint(user) playsound(loc, src.hitsound, 30, 1, -1) user.do_attack_animation(M) - + user.adjustStaminaLossBuffered(10)//CIT CHANGE - makes eyestabbing cost stamina if(M != user) @@ -605,12 +536,10 @@ GLOBAL_VAR_INIT(rpg_loot_items, FALSE) /obj/item/proc/remove_item_from_storage(atom/newLoc) //please use this if you're going to snowflake an item out of a obj/item/storage if(!newLoc) - return 0 - if(istype(loc, /obj/item/storage)) - var/obj/item/storage/S = loc - S.remove_from_storage(src,newLoc) - return 1 - return 0 + return FALSE + if(loc.SendSignal(COMSIG_CONTAINS_STORAGE)) + return loc.SendSignal(COMSIG_TRY_STORAGE_TAKE, src, newLoc, TRUE) + return FALSE /obj/item/proc/get_belt_overlay() //Returns the icon used for overlaying the object on a belt return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', icon_state) diff --git a/code/game/objects/items/blueprints.dm b/code/game/objects/items/blueprints.dm index 9edd19795c..a634f2a4ce 100644 --- a/code/game/objects/items/blueprints.dm +++ b/code/game/objects/items/blueprints.dm @@ -193,12 +193,11 @@ to_chat(usr, "The given name is too long. The area's name is unchanged.") return set_area_machinery_title(A,str,prevname) - for(var/area/RA in A.related) - RA.name = str - if(RA.firedoors) - for(var/D in RA.firedoors) - var/obj/machinery/door/firedoor/FD = D - FD.CalculateAffectingAreas() + A.name = str + if(A.firedoors) + for(var/D in A.firedoors) + var/obj/machinery/door/firedoor/FD = D + FD.CalculateAffectingAreas() to_chat(usr, "You rename the '[prevname]' to '[str]'.") log_game("[key_name(usr)] has renamed [prevname] to [str]") A.update_areasize() @@ -209,17 +208,16 @@ /obj/item/areaeditor/proc/set_area_machinery_title(area/A,title,oldtitle) if(!oldtitle) // or replacetext goes to infinite loop return - for(var/area/RA in A.related) - for(var/obj/machinery/airalarm/M in RA) - M.name = replacetext(M.name,oldtitle,title) - for(var/obj/machinery/power/apc/M in RA) - M.name = replacetext(M.name,oldtitle,title) - for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/M in RA) - M.name = replacetext(M.name,oldtitle,title) - for(var/obj/machinery/atmospherics/components/unary/vent_pump/M in RA) - M.name = replacetext(M.name,oldtitle,title) - for(var/obj/machinery/door/M in RA) - M.name = replacetext(M.name,oldtitle,title) + for(var/obj/machinery/airalarm/M in A) + M.name = replacetext(M.name,oldtitle,title) + for(var/obj/machinery/power/apc/M in A) + M.name = replacetext(M.name,oldtitle,title) + for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/M in A) + M.name = replacetext(M.name,oldtitle,title) + for(var/obj/machinery/atmospherics/components/unary/vent_pump/M in A) + M.name = replacetext(M.name,oldtitle,title) + for(var/obj/machinery/door/M in A) + M.name = replacetext(M.name,oldtitle,title) //TODO: much much more. Unnamed airlocks, cameras, etc. //Blueprint Subtypes diff --git a/code/game/objects/items/clown.dm b/code/game/objects/items/clown.dm deleted file mode 100644 index eb4c1a570e..0000000000 --- a/code/game/objects/items/clown.dm +++ /dev/null @@ -1,46 +0,0 @@ - -/obj/item/pie_cannon - name = "pie cannon" - desc = "Load cream pie for optimal results" - force = 10 - icon_state = "piecannon" - item_state = "powerfist" - var/obj/item/reagent_containers/food/snacks/pie/loaded = null - -/obj/item/pie_cannon/attackby(obj/item/I, mob/living/L) - if(istype(I, /obj/item/reagent_containers/food/snacks/pie)) - if(!loaded) - L.transferItemToLoc(I, src) - loaded = I - to_chat(L, "You load the [I] into the [src]!") - return - return ..() - -/obj/item/pie_cannon/afterattack(atom/target, mob/living/user, flag, params) - if(!loaded) - return ..() - var/obj/item/projectile/pie/launched = new /obj/item/projectile/pie(src) - launched.P = loaded - loaded.forceMove(launched) - launched.appearance = loaded.appearance - loaded = null - launched.preparePixelProjectile(target, get_turf(target), user, params, 0) - launched.forceMove(get_turf(src)) - launched.fire() - user.visible_message("[user] fires the [src] at [target]!") - -/obj/item/projectile/pie - name = "pie" - desc = "Think fast!" - var/obj/item/reagent_containers/food/snacks/pie/P = null - -/obj/item/projectile/pie/on_hit(atom/A) - . = ..() - if(P) - A.visible_message("[P] smashes into [A] at high velocity!") - P.forceMove(get_turf(A)) - P.throw_impact(A) - if(ismovableatom(A)) - var/atom/movable/AM = A - if(!AM.anchored) - AM.throw_at(get_edge_target_turf(get_dir(src, AM), 3, 2)) diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm index 0abdc9a7c4..7480f7b489 100644 --- a/code/game/objects/items/crayons.dm +++ b/code/game/objects/items/crayons.dm @@ -458,13 +458,14 @@ icon = 'icons/obj/crayons.dmi' icon_state = "crayonbox" w_class = WEIGHT_CLASS_SMALL - storage_slots = 7 - can_hold = list( - /obj/item/toy/crayon - ) -/obj/item/storage/crayons/New() - ..() +/obj/item/storage/crayons/Initialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 7 + STR.can_hold = typecacheof(list(/obj/item/toy/crayon)) + +/obj/item/storage/crayons/PopulateContents() new /obj/item/toy/crayon/red(src) new /obj/item/toy/crayon/orange(src) new /obj/item/toy/crayon/yellow(src) diff --git a/code/game/objects/items/devices/PDA/cart.dm b/code/game/objects/items/devices/PDA/cart.dm index 318aaa9e24..e7d9750a3b 100644 --- a/code/game/objects/items/devices/PDA/cart.dm +++ b/code/game/objects/items/devices/PDA/cart.dm @@ -1,18 +1,18 @@ -#define CART_SECURITY (1<<0) -#define CART_ENGINE (1<<1) -#define CART_ATMOS (1<<2) -#define CART_MEDICAL (1<<3) -#define CART_MANIFEST (1<<4) -#define CART_CLOWN (1<<5) -#define CART_MIME (1<<6) -#define CART_JANITOR (1<<7) +#define CART_SECURITY (1<<0) +#define CART_ENGINE (1<<1) +#define CART_ATMOS (1<<2) +#define CART_MEDICAL (1<<3) +#define CART_MANIFEST (1<<4) +#define CART_CLOWN (1<<5) +#define CART_MIME (1<<6) +#define CART_JANITOR (1<<7) #define CART_REAGENT_SCANNER (1<<8) -#define CART_NEWSCASTER (1<<9) -#define CART_REMOTE_DOOR (1<<10) -#define CART_STATUS_DISPLAY (1<<11) -#define CART_QUARTERMASTER (1<<12) -#define CART_HYDROPONICS (1<<13) -#define CART_DRONEPHONE (1<<14) +#define CART_NEWSCASTER (1<<9) +#define CART_REMOTE_DOOR (1<<10) +#define CART_STATUS_DISPLAY (1<<11) +#define CART_QUARTERMASTER (1<<12) +#define CART_HYDROPONICS (1<<13) +#define CART_DRONEPHONE (1<<14) /obj/item/cartridge diff --git a/code/game/objects/items/granters.dm b/code/game/objects/items/granters.dm index 7c90f07115..cf11ac7640 100644 --- a/code/game/objects/items/granters.dm +++ b/code/game/objects/items/granters.dm @@ -59,8 +59,8 @@ return if(do_after(user,50, user)) to_chat(user, "You feel like you've got a good handle on [actionname]!") - reading = FALSE G.Grant(user) + reading = FALSE /obj/item/book/granter/action/drink_fling granted_action = /datum/action/innate/drink_fling @@ -121,10 +121,10 @@ return if(do_after(user,50, user)) to_chat(user, "You feel like you've experienced enough to cast [spellname]!") - reading = FALSE user.mind.AddSpell(S) user.log_message("learned the spell [spellname] ([S]).", INDIVIDUAL_ATTACK_LOG) onlearned(user) + reading = FALSE /obj/item/book/granter/spell/recoil(mob/user) user.visible_message("[src] glows in a black light!") @@ -328,10 +328,10 @@ return if(do_after(user,50, user)) to_chat(user, "[greet]") - reading = FALSE MA.teach(user) user.log_message("learned the martial art [martialname] ([MA]).", INDIVIDUAL_ATTACK_LOG) onlearned(user) + reading = FALSE /obj/item/book/granter/martial/cqc martial = /datum/martial_art/cqc diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm index f2daf58b1a..4a9e136182 100644 --- a/code/game/objects/items/grenades/chem_grenade.dm +++ b/code/game/objects/items/grenades/chem_grenade.dm @@ -579,3 +579,7 @@ beakers += B1 beakers += B2 + +#undef READY +#undef WIRED +#undef EMPTY diff --git a/code/game/objects/items/grenades/plastic.dm b/code/game/objects/items/grenades/plastic.dm index 3c4910abc0..6d15992d24 100644 --- a/code/game/objects/items/grenades/plastic.dm +++ b/code/game/objects/items/grenades/plastic.dm @@ -214,12 +214,8 @@ return if(loc == AM) return - if((istype(AM, /obj/item/storage/)) && !((istype(AM, /obj/item/storage/secure)) || (istype(AM, /obj/item/storage/lockbox)))) //If its storage but not secure storage OR a lockbox, then place it inside. + if(AM.SendSignal(COMSIG_CONTAINS_STORAGE) && !AM.SendSignal(COMSIG_IS_STORAGE_LOCKED)) return - if((istype(AM, /obj/item/storage/secure)) || (istype(AM, /obj/item/storage/lockbox))) - var/obj/item/storage/secure/S = AM - if(!S.locked) //Literal hacks, this works for lockboxes despite incorrect type casting, because they both share the locked var. But if its unlocked, place it inside, otherwise PLANTING C4! - return to_chat(user, "You start planting the bomb...") diff --git a/code/game/objects/items/implants/implant_storage.dm b/code/game/objects/items/implants/implant_storage.dm index 049635707e..787c246ddf 100644 --- a/code/game/objects/items/implants/implant_storage.dm +++ b/code/game/objects/items/implants/implant_storage.dm @@ -1,46 +1,30 @@ -/obj/item/storage/internal/implant - name = "bluespace pocket" - max_w_class = WEIGHT_CLASS_NORMAL - max_combined_w_class = 6 - cant_hold = list(/obj/item/disk/nuclear) - silent = TRUE - - /obj/item/implant/storage name = "storage implant" desc = "Stores up to two big items in a bluespace pocket." icon_state = "storage" item_color = "r" - var/obj/item/storage/internal/implant/storage - -/obj/item/implant/storage/New() - ..() - storage = new /obj/item/storage/internal/implant(src) + var/max_slot_stacking = 4 /obj/item/implant/storage/activate() - storage.MouseDrop(imp_in) + SendSignal(COMSIG_TRY_STORAGE_SHOW, imp_in, TRUE) /obj/item/implant/storage/removed(source, silent = FALSE, special = 0) - if(..()) + . = ..() + if(.) if(!special) - storage.close_all() - for(var/obj/item/I in storage) - storage.remove_from_storage(I, get_turf(source)) - return 1 + qdel(GetComponent(/datum/component/storage/concrete/implant)) /obj/item/implant/storage/implant(mob/living/target, mob/user, silent = FALSE) for(var/X in target.implants) if(istype(X, type)) var/obj/item/implant/storage/imp_e = X - imp_e.storage.storage_slots += storage.storage_slots - imp_e.storage.max_combined_w_class += storage.max_combined_w_class - imp_e.storage.contents += storage.contents - - storage.close_all() - storage.show_to(target) - - qdel(src) - return 1 + GET_COMPONENT_FROM(STR, /datum/component/storage, imp_e) + if(!STR || (STR && STR.max_items < max_slot_stacking)) + imp_e.AddComponent(/datum/component/storage/concrete/implant) + qdel(src) + return TRUE + return FALSE + AddComponent(/datum/component/storage/concrete/implant) return ..() diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index 6ae43f4958..ac04b10ddc 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -216,13 +216,13 @@ w_class = WEIGHT_CLASS_BULKY force = 0.001 armour_penetration = 1000 - var/obj/machinery/power/supermatter_shard/shard + var/obj/machinery/power/supermatter_crystal/shard var/balanced = 1 force_string = "INFINITE" /obj/item/melee/supermatter_sword/Initialize() . = ..() - shard = new /obj/machinery/power/supermatter_shard(src) + shard = new /obj/machinery/power/supermatter_crystal(src) qdel(shard.countdown) shard.countdown = null START_PROCESSING(SSobj, src) @@ -339,7 +339,7 @@ /obj/item/melee/roastingstick/Initialize() . = ..() if (!ovens) - ovens = typecacheof(list(/obj/singularity, /obj/machinery/power/supermatter_shard/crystal, /obj/structure/bonfire, /obj/structure/destructible/clockwork/massive/ratvar)) + ovens = typecacheof(list(/obj/singularity, /obj/machinery/power/supermatter_crystal/crystal, /obj/structure/bonfire, /obj/structure/destructible/clockwork/massive/ratvar)) /obj/item/melee/roastingstick/attack_self(mob/user) on = !on diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm index 1a4c2f5674..0f926b4ee3 100644 --- a/code/game/objects/items/religion.dm +++ b/code/game/objects/items/religion.dm @@ -212,9 +212,13 @@ /obj/item/storage/backpack/bannerpack name = "nanotrasen banner backpack" desc = "It's a backpack with lots of extra room. A banner with Nanotrasen's logo is attached, that can't be removed." - max_combined_w_class = 27 //6 more then normal, for the tradeoff of declaring yourself an antag at all times. icon_state = "bannerpack" +/obj/item/storage/backpack/bannerpack/Initialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 27 //6 more then normal, for the tradeoff of declaring yourself an antag at all times. + /obj/item/storage/backpack/bannerpack/red name = "red banner backpack" desc = "It's a backpack with lots of extra room. A red banner is attached, that can't be removed." diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 63bfe6eeb3..854031b1f4 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -14,14 +14,20 @@ // if module is reset var/one_use = FALSE -/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R) +/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R, user = usr) if(R.stat == DEAD) - to_chat(usr, "[src] will not function on a deceased cyborg.") - return 1 + to_chat(user, "[src] will not function on a deceased cyborg.") + return FALSE if(module_type && !istype(R.module, module_type)) to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!") - to_chat(usr, "There's no mounting point for the module!") - return 1 + to_chat(user, "There's no mounting point for the module!") + return FALSE + return TRUE + +/obj/item/borg/upgrade/proc/deactivate(mob/living/silicon/robot/R, user = usr) + if (!(src in R.upgrades)) + return FALSE + return TRUE /obj/item/borg/upgrade/rename name = "cyborg reclassification board" @@ -34,18 +40,13 @@ heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN) /obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R) - if(..()) - return - - var/oldname = R.real_name - - R.custom_name = heldname - R.updatename() - if(oldname == R.real_name) - R.notify_ai(RENAME, oldname, R.real_name) - - return 1 - + . = ..() + if(.) + var/oldname = R.real_name + R.custom_name = heldname + R.updatename() + if(oldname == R.real_name) + R.notify_ai(RENAME, oldname, R.real_name) /obj/item/borg/upgrade/restart name = "cyborg emergency reboot module" @@ -53,10 +54,10 @@ icon_state = "cyborg_upgrade1" one_use = TRUE -/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R) +/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R, user = usr) if(R.health < 0) - to_chat(usr, "You have to repair the cyborg before using this module!") - return 0 + to_chat(user, "You have to repair the cyborg before using this module!") + return FALSE if(R.mind) R.mind.grab_ghost() @@ -64,25 +65,26 @@ R.revive() - return 1 - /obj/item/borg/upgrade/vtec name = "cyborg VTEC module" desc = "Used to kick in a cyborg's VTEC systems, increasing their speed." icon_state = "cyborg_upgrade2" require_module = 1 -/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R) - if(..()) - return - if(R.speed < 0) - to_chat(R, "A VTEC unit is already installed!") - to_chat(usr, "There's no room for another VTEC unit!") - return +/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + if(R.speed < 0) + to_chat(R, "A VTEC unit is already installed!") + to_chat(user, "There's no room for another VTEC unit!") + return FALSE - R.speed = -2 // Gotta go fast. + R.speed = -2 // Gotta go fast. - return 1 +/obj/item/borg/upgrade/vtec/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + R.speed = initial(R.speed) /obj/item/borg/upgrade/disablercooler name = "cyborg rapid disabler cooling module" @@ -91,38 +93,46 @@ require_module = 1 module_type = /obj/item/robot_module/security -/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules + if(!T) + to_chat(user, "There's no disabler in this unit!") + return FALSE + if(T.charge_delay <= 2) + to_chat(R, "A cooling unit is already installed!") + to_chat(user, "There's no room for another cooling unit!") + return FALSE - var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules - if(!T) - to_chat(usr, "There's no disabler in this unit!") - return - if(T.charge_delay <= 2) - to_chat(R, "A cooling unit is already installed!") - to_chat(usr, "There's no room for another cooling unit!") - return + T.charge_delay = max(2 , T.charge_delay - 4) - T.charge_delay = max(2 , T.charge_delay - 4) - - return 1 +/obj/item/borg/upgrade/disablercooler/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules + if(!T) + return FALSE + T.charge_delay = initial(T.charge_delay) /obj/item/borg/upgrade/thrusters name = "ion thruster upgrade" desc = "An energy-operated thruster system for cyborgs." icon_state = "cyborg_upgrade3" -/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + if(R.ionpulse) + to_chat(user, "This unit already has ion thrusters installed!") + return FALSE - if(R.ionpulse) - to_chat(usr, "This unit already has ion thrusters installed!") - return + R.ionpulse = TRUE - R.ionpulse = TRUE - return 1 +/obj/item/borg/upgrade/thrusters/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + R.ionpulse = FALSE /obj/item/borg/upgrade/ddrill name = "mining cyborg diamond drill" @@ -131,19 +141,30 @@ require_module = 1 module_type = /obj/item/robot_module/miner -/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + for(var/obj/item/pickaxe/drill/cyborg/D in R.module) + R.module.remove_module(D, TRUE) + for(var/obj/item/shovel/S in R.module) + R.module.remove_module(S, TRUE) - for(var/obj/item/pickaxe/drill/cyborg/D in R.module) - R.module.remove_module(D, TRUE) - for(var/obj/item/shovel/S in R.module) - R.module.remove_module(S, TRUE) + var/obj/item/pickaxe/drill/cyborg/diamond/DD = new /obj/item/pickaxe/drill/cyborg/diamond(R.module) + R.module.basic_modules += DD + R.module.add_module(DD, FALSE, TRUE) - var/obj/item/pickaxe/drill/cyborg/diamond/DD = new /obj/item/pickaxe/drill/cyborg/diamond(R.module) - R.module.basic_modules += DD - R.module.add_module(DD, FALSE, TRUE) - return 1 +/obj/item/borg/upgrade/ddrill/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + for(var/obj/item/pickaxe/drill/cyborg/diamond/DD in R.module) + R.module.remove_module(DD, TRUE) + + var/obj/item/pickaxe/drill/cyborg/D = new (R.module) + R.module.basic_modules += D + R.module.add_module(D, FALSE, TRUE) + var/obj/item/shovel/S = new (R.module) + R.module.basic_modules += S + R.module.add_module(S, FALSE, TRUE) /obj/item/borg/upgrade/soh name = "mining cyborg satchel of holding" @@ -153,16 +174,24 @@ module_type = /obj/item/robot_module/miner /obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R) - if(..()) - return + . = ..() + if(.) + for(var/obj/item/storage/bag/ore/cyborg/S in R.module) + R.module.remove_module(S, TRUE) - for(var/obj/item/storage/bag/ore/cyborg/S in R.module) - R.module.remove_module(S, TRUE) + var/obj/item/storage/bag/ore/holding/H = new /obj/item/storage/bag/ore/holding(R.module) + R.module.basic_modules += H + R.module.add_module(H, FALSE, TRUE) - var/obj/item/storage/bag/ore/holding/H = new /obj/item/storage/bag/ore/holding(R.module) - R.module.basic_modules += H - R.module.add_module(H, FALSE, TRUE) - return 1 +/obj/item/borg/upgrade/soh/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + for(var/obj/item/storage/bag/ore/holding/H in R.module) + R.module.remove_module(H, TRUE) + + var/obj/item/storage/bag/ore/cyborg/S = new (R.module) + R.module.basic_modules += S + R.module.add_module(S, FALSE, TRUE) /obj/item/borg/upgrade/syndicate name = "illegal equipment module" @@ -170,16 +199,20 @@ icon_state = "cyborg_upgrade3" require_module = 1 -/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + if(R.emagged) + return FALSE - if(R.emagged) - return + R.SetEmagged(1) - R.SetEmagged(1) + return TRUE - return 1 +/obj/item/borg/upgrade/syndicate/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + R.SetEmagged(FALSE) /obj/item/borg/upgrade/lavaproof name = "mining cyborg lavaproof tracks" @@ -189,11 +222,15 @@ require_module = 1 module_type = /obj/item/robot_module/miner -/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R) - if(..()) - return - R.weather_immunities += "lava" - return 1 +/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + R.weather_immunities += "lava" + +/obj/item/borg/upgrade/lavaproof/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + R.weather_immunities -= "lava" /obj/item/borg/upgrade/selfrepair name = "self-repair module" @@ -208,20 +245,26 @@ var/mob/living/silicon/robot/cyborg var/datum/action/toggle_action -/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + var/obj/item/borg/upgrade/selfrepair/U = locate() in R + if(U) + to_chat(user, "This unit is already equipped with a self-repair module.") + return FALSE - var/obj/item/borg/upgrade/selfrepair/U = locate() in R - if(U) - to_chat(usr, "This unit is already equipped with a self-repair module.") - return 0 + cyborg = R + icon_state = "selfrepair_off" + toggle_action = new /datum/action/item_action/toggle(src) + toggle_action.Grant(R) - cyborg = R - icon_state = "selfrepair_off" - toggle_action = new /datum/action/item_action/toggle(src) - toggle_action.Grant(R) - return 1 +/obj/item/borg/upgrade/selfrepair/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + toggle_action.Remove(cyborg) + QDEL_NULL(toggle_action) + cyborg = null + deactivate_sr() /obj/item/borg/upgrade/selfrepair/dropped() addtimer(CALLBACK(src, .proc/check_dropped), 1) @@ -231,7 +274,7 @@ toggle_action.Remove(cyborg) QDEL_NULL(toggle_action) cyborg = null - deactivate() + deactivate_sr() /obj/item/borg/upgrade/selfrepair/ui_action_click() on = !on @@ -252,7 +295,7 @@ else icon_state = "cyborg_upgrade5" -/obj/item/borg/upgrade/selfrepair/proc/deactivate() +/obj/item/borg/upgrade/selfrepair/proc/deactivate_sr() STOP_PROCESSING(SSobj, src) on = FALSE update_icon() @@ -265,12 +308,12 @@ if(cyborg && (cyborg.stat != DEAD) && on) if(!cyborg.cell) to_chat(cyborg, "Self-repair module deactivated. Please, insert the power cell.") - deactivate() + deactivate_sr() return if(cyborg.cell.charge < powercost * 2) to_chat(cyborg, "Self-repair module deactivated. Please recharge.") - deactivate() + deactivate_sr() return if(cyborg.health < cyborg.maxHealth) @@ -297,7 +340,7 @@ to_chat(cyborg, "Self-repair is active in [msgmode] mode.") msg_cooldown = world.time else - deactivate() + deactivate_sr() /obj/item/borg/upgrade/hypospray name = "medical cyborg hypospray advanced synthesiser" @@ -308,15 +351,21 @@ module_type = /obj/item/robot_module/medical var/list/additional_reagents = list() -/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R) - if(..()) - return - for(var/obj/item/reagent_containers/borghypo/H in R.module.modules) - if(H.accepts_reagent_upgrades) - for(var/re in additional_reagents) - H.add_reagent(re) +/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + for(var/obj/item/reagent_containers/borghypo/H in R.module.modules) + if(H.accepts_reagent_upgrades) + for(var/re in additional_reagents) + H.add_reagent(re) - return 1 +/obj/item/borg/upgrade/hypospray/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + for(var/obj/item/reagent_containers/borghypo/H in R.module.modules) + if(H.accepts_reagent_upgrades) + for(var/re in additional_reagents) + H.del_reagent(re) /obj/item/borg/upgrade/hypospray/expanded name = "medical cyborg expanded hypospray" @@ -338,19 +387,22 @@ pierce armor and thick material." icon_state = "cyborg_upgrade3" -/obj/item/borg/upgrade/piercing_hypospray/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/piercing_hypospray/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + var/found_hypo = FALSE + for(var/obj/item/reagent_containers/borghypo/H in R.module.modules) + H.bypass_protection = TRUE + found_hypo = TRUE - var/found_hypo = FALSE - for(var/obj/item/reagent_containers/borghypo/H in R.module.modules) - H.bypass_protection = TRUE - found_hypo = TRUE + if(!found_hypo) + return FALSE - if(!found_hypo) - return - - return 1 +/obj/item/borg/upgrade/piercing_hypospray/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + for(var/obj/item/reagent_containers/borghypo/H in R.module.modules) + H.bypass_protection = initial(H.bypass_protection) /obj/item/borg/upgrade/defib name = "medical cyborg defibrillator" @@ -360,66 +412,81 @@ require_module = 1 module_type = /obj/item/robot_module/medical -/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + var/obj/item/twohanded/shockpaddles/cyborg/S = new(R.module) + R.module.basic_modules += S + R.module.add_module(S, FALSE, TRUE) - var/obj/item/twohanded/shockpaddles/cyborg/S = new(R.module) - R.module.basic_modules += S - R.module.add_module(S, FALSE, TRUE) - - return 1 +/obj/item/borg/upgrade/defib/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + var/obj/item/twohanded/shockpaddles/cyborg/S = locate() in R.module + R.module.remove_module(S, TRUE) /obj/item/borg/upgrade/ai name = "B.O.R.I.S. module" desc = "Bluespace Optimized Remote Intelligence Synchronization. An uplink device which takes the place of an MMI in cyborg endoskeletons, creating a robotic shell controlled by an AI." icon_state = "boris" -/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/R) - if(..()) - return - if(R.shell) - to_chat(usr, "This unit is already an AI shell!") - return - if(R.key) //You cannot replace a player unless the key is completely removed. - to_chat(usr, "Intelligence patterns detected in this [R.braintype]. Aborting.") - return +/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) + if(R.shell) + to_chat(user, "This unit is already an AI shell!") + return FALSE + if(R.key) //You cannot replace a player unless the key is completely removed. + to_chat(user, "Intelligence patterns detected in this [R.braintype]. Aborting.") + return FALSE - R.make_shell(src) - return TRUE + R.make_shell(src) + +/obj/item/borg/upgrade/ai/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + if(R.shell) + R.undeploy() + R.notify_ai(AI_SHELL) /obj/item/borg/upgrade/expand name = "borg expander" desc = "A cyborg resizer, it makes a cyborg huge." icon_state = "cyborg_upgrade3" -/obj/item/borg/upgrade/expand/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/expand/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) - if(R.hasExpanded) - to_chat(usr, "This unit already has an expand module installed!") - return + if(R.hasExpanded) + to_chat(usr, "This unit already has an expand module installed!") + return FALSE - R.notransform = TRUE - var/prev_lockcharge = R.lockcharge - R.SetLockdown(1) - R.anchored = TRUE - var/datum/effect_system/smoke_spread/smoke = new - smoke.set_up(1, R.loc) - smoke.start() - sleep(2) - for(var/i in 1 to 4) - playsound(R, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, 1, -1) - sleep(12) - if(!prev_lockcharge) - R.SetLockdown(0) - R.anchored = FALSE - R.notransform = FALSE - R.resize = 2 - R.hasExpanded = TRUE - R.update_transform() - return TRUE + R.notransform = TRUE + var/prev_lockcharge = R.lockcharge + R.SetLockdown(1) + R.anchored = TRUE + var/datum/effect_system/smoke_spread/smoke = new + smoke.set_up(1, R.loc) + smoke.start() + sleep(2) + for(var/i in 1 to 4) + playsound(R, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, 1, -1) + sleep(12) + if(!prev_lockcharge) + R.SetLockdown(0) + R.anchored = FALSE + R.notransform = FALSE + R.resize = 2 + R.hasExpanded = TRUE + R.update_transform() + +/obj/item/borg/upgrade/expand/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + R.resize = 0.5 + R.hasExpanded = FALSE + R.update_transform() /obj/item/borg/upgrade/rped name = "engineering cyborg RPED" @@ -429,19 +496,25 @@ require_module = TRUE module_type = /obj/item/robot_module/engineering -/obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) - var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R - if(RPED) - to_chat(usr, "This unit is already equipped with a RPED module.") - return FALSE + var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R + if(RPED) + to_chat(user, "This unit is already equipped with a RPED module.") + return FALSE - RPED = new(R.module) - R.module.basic_modules += RPED - R.module.add_module(RPED, FALSE, TRUE) - return TRUE + RPED = new(R.module) + R.module.basic_modules += RPED + R.module.add_module(RPED, FALSE, TRUE) + +/obj/item/borg/upgrade/rped/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R.module + if (RPED) + R.module.remove_module(RPED, TRUE) /obj/item/borg/upgrade/pinpointer name = "medical cyborg crew pinpointer" @@ -451,16 +524,22 @@ require_module = TRUE module_type = /obj/item/robot_module/medical -/obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R) - if(..()) - return +/obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr) + . = ..() + if(.) - var/obj/item/pinpointer/crew/PP = locate() in R - if(PP) - to_chat(usr, "This unit is already equipped with a pinpointer module.") - return FALSE + var/obj/item/pinpointer/crew/PP = locate() in R + if(PP) + to_chat(user, "This unit is already equipped with a pinpointer module.") + return FALSE - PP = new(R.module) - R.module.basic_modules += PP - R.module.add_module(PP, FALSE, TRUE) - return TRUE + PP = new(R.module) + R.module.basic_modules += PP + R.module.add_module(PP, FALSE, TRUE) + +/obj/item/borg/upgrade/pinpointer/deactivate(mob/living/silicon/robot/R, user = usr) + . = ..() + if (.) + var/obj/item/pinpointer/crew/PP = locate() in R.module + if (PP) + R.module.remove_module(PP, TRUE) diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm index 6bf32210bd..b1afc7bd18 100644 --- a/code/game/objects/items/stacks/stack.dm +++ b/code/game/objects/items/stacks/stack.dm @@ -415,4 +415,4 @@ /datum/stack_recipe_list/New(title, recipes) src.title = title - src.recipes = recipes \ No newline at end of file + src.recipes = recipes diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 26c2c0b9db..a236ebeff6 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -18,32 +18,42 @@ 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 = NONE max_integrity = 300 +/obj/item/storage/backpack/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 21 + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_items = 21 + + /* * Backpack Types */ -/obj/item/storage/backpack/old - max_combined_w_class = 12 +/obj/item/storage/backpack/old/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.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." icon_state = "holdingpack" item_state = "holdingpack" - max_w_class = WEIGHT_CLASS_GIGANTIC - max_combined_w_class = 35 resistance_flags = FIRE_PROOF flags_2 = NO_MAT_REDEMPTION_2 - 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) + component_type = /datum/component/storage/concrete/bluespace/bag_of_holding +/obj/item/storage/backpack/holding/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.allow_big_nesting = TRUE + STR.max_w_class = WEIGHT_CLASS_GIGANTIC + STR.max_combined_w_class = 35 /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.") @@ -54,57 +64,23 @@ 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/living/user) - if((istype(W, /obj/item/storage/backpack/holding) || count_by_type(W.GetAllContents(), /obj/item/storage/backpack/holding))) - var/turf/loccheck = get_turf(src) - if(is_reebe(loccheck.z)) - user.visible_message("An unseen force knocks [user] to the ground!", "\"I think not!\"") - user.Knockdown(60) - return - 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.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...") @@ -151,7 +127,6 @@ desc = "It's a special backpack made exclusively for Nanotrasen officers." icon_state = "captainpack" item_state = "captainpack" - resistance_flags = NONE /obj/item/storage/backpack/industrial name = "industrial backpack" @@ -183,7 +158,6 @@ desc = "A specially designed backpack. It's fire resistant and smells vaguely of plasma." icon_state = "toxpack" item_state = "toxpack" - resistance_flags = NONE /obj/item/storage/backpack/virology name = "virology backpack" @@ -191,7 +165,6 @@ icon_state = "viropack" item_state = "viropack" - /* * Satchel Types */ @@ -206,7 +179,6 @@ name = "leather satchel" desc = "It's a very fancy satchel made with fine leather." icon_state = "satchel" - resistance_flags = NONE /obj/item/storage/backpack/satchel/leather/withwallet/PopulateContents() new /obj/item/storage/wallet/random(src) @@ -216,7 +188,6 @@ desc = "A tough satchel with extra pockets." icon_state = "satchel-eng" item_state = "engiepack" - resistance_flags = NONE /obj/item/storage/backpack/satchel/med name = "medical satchel" @@ -247,7 +218,6 @@ desc = "Useful for holding research materials." icon_state = "satchel-tox" item_state = "satchel-tox" - resistance_flags = NONE /obj/item/storage/backpack/satchel/hyd name = "botanist satchel" @@ -272,18 +242,26 @@ desc = "An exclusive satchel for Nanotrasen officers." icon_state = "satchel-cap" item_state = "captainpack" - resistance_flags = NONE /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 + component_type = /datum/component/storage/concrete/secret_satchel -/obj/item/storage/backpack/satchel/flat/hide(var/intact) +/obj/item/storage/backpack/stachel/flat/Initialize() + . = ..() + SSpersistence.new_secret_satchels += src + +/obj/item/storage/backpack/satchel/flat/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 15 + STR.cant_hold = typecacheof(list(/obj/item/storage/backpack/satchel/flat)) //muh recursive backpacks + +/obj/item/storage/backpack/satchel/flat/hide(intact) if(intact) invisibility = INVISIBILITY_MAXIMUM anchored = TRUE //otherwise you can start pulling, cover it, and drag around an invisible backpack. @@ -293,10 +271,6 @@ 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) @@ -308,7 +282,7 @@ /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 + var/revealed = FALSE /obj/item/storage/backpack/satchel/flat/secret/Initialize() . = ..() @@ -324,13 +298,7 @@ new reward(src) for(var/R in reward_all_of_these) new R(src) - revealed = 1 - -/obj/item/storage/backpack/satchel/flat/can_be_inserted(obj/item/W, stop_messages = 0, mob/user) - if(SSpersistence.spawned_objects[W]) - to_chat(user, "[W] is unstable after its journey through space and time, it wouldn't survive another trip.") - return FALSE - return ..() + revealed = TRUE /obj/item/storage/backpack/duffelbag name = "duffel bag" @@ -338,14 +306,17 @@ icon_state = "duffel" item_state = "duffel" slowdown = 1 - max_combined_w_class = 30 + +/obj/item/storage/backpack/duffelbag/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.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 = NONE /obj/item/storage/backpack/duffelbag/med name = "medical duffel bag" @@ -393,7 +364,6 @@ desc = "A large duffel bag for holding extra tools and supplies." icon_state = "duffel-eng" item_state = "duffel-eng" - resistance_flags = NONE /obj/item/storage/backpack/duffelbag/drone name = "drone duffel bag" @@ -426,9 +396,13 @@ desc = "A large duffel bag for holding extra tactical supplies." icon_state = "duffel-syndie" item_state = "duffel-syndieammo" - silent = 1 slowdown = 0 +/obj/item/storage/backpack/duffelbag/syndie/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.silent = TRUE + /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" @@ -561,9 +535,11 @@ new /obj/item/grenade/syndieminibomb(src) // For ClownOps. -/obj/item/storage/backpack/duffelbag/clown/syndie +/obj/item/storage/backpack/duffelbag/clown/syndie/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) slowdown = 0 - silent = TRUE + STR.silent = TRUE /obj/item/storage/backpack/duffelbag/clown/syndie/PopulateContents() new /obj/item/device/pda/clown(src) diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm index c8f6a9ff13..5c6a354356 100644 --- a/code/game/objects/items/storage/bags.dm +++ b/code/game/objects/items/storage/bags.dm @@ -17,12 +17,16 @@ // Generic non-item /obj/item/storage/bag - allow_quick_gather = 1 - allow_quick_empty = 1 - display_contents_with_number = 1 // should work fine now - use_to_pickup = 1 slot_flags = SLOT_BELT +/obj/item/storage/bag/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.allow_quick_gather = TRUE + STR.allow_quick_empty = TRUE + STR.display_numerical_stacking = TRUE + STR.click_gather = TRUE + // ----------------------------- // Trash bag // ----------------------------- @@ -36,11 +40,14 @@ righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi' w_class = WEIGHT_CLASS_BULKY - max_w_class = WEIGHT_CLASS_SMALL - max_combined_w_class = 30 - storage_slots = 30 - can_hold = list() // any - cant_hold = list(/obj/item/disk/nuclear) + +/obj/item/storage/bag/trash/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_SMALL + STR.max_combined_w_class = 30 + STR.max_items = 30 + STR.cant_hold = typecacheof(list(/obj/item/disk/nuclear)) /obj/item/storage/bag/trash/suicide_act(mob/user) user.visible_message("[user] puts [src] over [user.p_their()] head and starts chomping at the insides! Disgusting!") @@ -70,10 +77,14 @@ name = "trash bag of holding" desc = "The latest and greatest in custodial convenience, a trashbag that is capable of holding vast quantities of garbage." icon_state = "bluetrashbag" - max_combined_w_class = 60 - storage_slots = 60 flags_2 = NO_MAT_REDEMPTION_2 +/obj/item/storage/bag/trash/bluespace/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 60 + STR.max_items = 60 + // ----------------------------- // Mining Satchel // ----------------------------- @@ -85,13 +96,18 @@ icon_state = "satchel" slot_flags = SLOT_BELT | SLOT_POCKET w_class = WEIGHT_CLASS_NORMAL - storage_slots = 8 - max_combined_w_class = 16 //Doesn't matter what this is, so long as it's more or equal to storage_slots * ore.w_class - max_w_class = WEIGHT_CLASS_HUGE - can_hold = list(/obj/item/stack/ore) + component_type = /datum/component/storage/concrete/stack var/spam_protection = FALSE //If this is TRUE, the holder won't receive any messages when they fail to pick up ore through crossing it var/datum/component/mobhook +/obj/item/storage/bag/ore/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage/concrete/stack) + STR.allow_quick_empty = TRUE + STR.can_hold = typecacheof(list(/obj/item/stack/ore)) + STR.max_w_class = WEIGHT_CLASS_HUGE + STR.max_combined_stack_amount = 50 + /obj/item/storage/bag/ore/equipped(mob/user) . = ..() if (mobhook && mobhook.parent != user) @@ -112,20 +128,21 @@ return if (istype(user.pulling, /obj/structure/ore_box)) box = user.pulling - for(var/A in tile) - if (!is_type_in_typecache(A, can_hold)) - continue - if (box) - user.transferItemToLoc(A, box) - show_message = TRUE - else if(can_be_inserted(A, TRUE, user)) - handle_item_insertion(A, TRUE, user) - show_message = TRUE - else - if(!spam_protection) - to_chat(user, "Your [name] is full and can't hold any more!") - spam_protection = TRUE + GET_COMPONENT(STR, /datum/component/storage) + if(STR) + for(var/A in tile) + if (!is_type_in_typecache(A, STR.can_hold)) continue + if (box) + user.transferItemToLoc(A, box) + show_message = TRUE + else if(SendSignal(COMSIG_TRY_STORAGE_INSERT, A, user, TRUE)) + show_message = TRUE + else + if(!spam_protection) + to_chat(user, "Your [name] is full and can't hold any more!") + spam_protection = TRUE + continue if(show_message) playsound(user, "rustle", 50, TRUE) if (box) @@ -142,10 +159,15 @@ /obj/item/storage/bag/ore/holding //miners, your messiah has arrived name = "mining satchel of holding" desc = "A revolution in convenience, this satchel allows for huge amounts of ore storage. It's been outfitted with anti-malfunction safety measures." - storage_slots = INFINITY - max_combined_w_class = INFINITY icon_state = "satchel_bspace" +/obj/item/storage/bag/ore/holding/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage/concrete/stack) + STR.max_items = INFINITY + STR.max_combined_w_class = INFINITY + STR.max_combined_stack_amount = INFINITY + // ----------------------------- // Plant bag // ----------------------------- @@ -154,13 +176,17 @@ name = "plant bag" icon = 'icons/obj/hydroponics/equipment.dmi' icon_state = "plantbag" - storage_slots = 100; //the number of plant pieces it can carry. - max_combined_w_class = 100 //Doesn't matter what this is, so long as it's more or equal to storage_slots * plants.w_class - max_w_class = WEIGHT_CLASS_NORMAL w_class = WEIGHT_CLASS_TINY - can_hold = list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb) resistance_flags = FLAMMABLE +/obj/item/storage/bag/plants/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 100 + STR.max_items = 100 + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/grown, /obj/item/seeds, /obj/item/grown, /obj/item/reagent_containers/honeycomb)) + //////// /obj/item/storage/bag/plants/portaseeder @@ -176,8 +202,6 @@ return for(var/obj/item/O in contents) seedify(O, 1) - close_all() - // ----------------------------- // Sheet Snatcher @@ -193,123 +217,15 @@ var/capacity = 300; //the number of sheets it can carry. w_class = WEIGHT_CLASS_NORMAL + component_type = /datum/component/storage/concrete/stack - allow_quick_empty = 1 // this function is superceded - -/obj/item/storage/bag/sheetsnatcher/can_be_inserted(obj/item/W, stop_messages = 0) - if(!istype(W, /obj/item/stack/sheet) || istype(W, /obj/item/stack/sheet/mineral/sandstone) || istype(W, /obj/item/stack/sheet/mineral/wood)) - if(!stop_messages) - to_chat(usr, "The snatcher does not accept [W].") - return 0 //I don't care, but the existing code rejects them for not being "sheets" *shrug* -Sayu - var/current = 0 - for(var/obj/item/stack/sheet/S in contents) - current += S.amount - if(capacity == current)//If it's full, you're done - if(!stop_messages) - to_chat(usr, "The snatcher is full.") - return 0 - return 1 - - -// Modified handle_item_insertion. Would prefer not to, but... -/obj/item/storage/bag/sheetsnatcher/handle_item_insertion(obj/item/W, prevent_warning = 0) - var/obj/item/stack/sheet/S = W - if(!istype(S)) - return 0 - - var/amount - var/inserted = 0 - var/current = 0 - for(var/obj/item/stack/sheet/S2 in contents) - current += S2.amount - if(capacity < current + S.amount)//If the stack will fill it up - amount = capacity - current - else - amount = S.amount - - for(var/obj/item/stack/sheet/sheet in contents) - if(S.type == sheet.type) // we are violating the amount limitation because these are not sane objects - sheet.amount += amount // they should only be removed through procs in this file, which split them up. - S.amount -= amount - inserted = 1 - break - - if(!inserted || !S.amount) - usr.dropItemToGround(S) - if (usr.client && usr.s_active != src) - usr.client.screen -= S - S.dropped(usr) - if(!S.amount) - qdel(S) - else - if(S.pulledby) - S.pulledby.stop_pulling() - S.forceMove(src) - - orient2hud(usr) - if(usr.s_active) - usr.s_active.show_to(usr) - update_icon() - return 1 - - -// Sets up numbered display to show the stack size of each stored mineral -// NOTE: numbered display is turned off currently because it's broken -/obj/item/storage/bag/sheetsnatcher/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/stack/sheet/I in contents) - adjusted_contents++ - var/datum/numbered_display/D = new/datum/numbered_display(I) - D.number = I.amount - numbered_contents.Add( D ) - - 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) - return - - -// Modified quick_empty verb drops appropriate sized stacks -/obj/item/storage/bag/sheetsnatcher/quick_empty() - var/location = get_turf(src) - for(var/obj/item/stack/sheet/S in contents) - while(S.amount) - var/obj/item/stack/sheet/N = new S.type(location) - var/stacksize = min(S.amount,N.max_amount) - N.amount = stacksize - S.amount -= stacksize - if(!S.amount) - qdel(S)// todo: there's probably something missing here - orient2hud(usr) - if(usr.s_active) - usr.s_active.show_to(usr) - update_icon() - -// Instead of removing -/obj/item/storage/bag/sheetsnatcher/remove_from_storage(obj/item/W, atom/new_location) - var/obj/item/stack/sheet/S = W - if(!istype(S)) - return 0 - - //I would prefer to drop a new stack, but the item/attack_hand code - // that calls this can't recieve a different object than you clicked on. - //Therefore, make a new stack internally that has the remainder. - // -Sayu - - if(S.amount > S.max_amount) - var/obj/item/stack/sheet/temp = new S.type(src) - temp.amount = S.amount - S.max_amount - S.amount = S.max_amount - - return ..(S,new_location) +/obj/item/storage/bag/sheetsnatcher/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage/concrete/stack) + STR.allow_quick_empty = TRUE + STR.can_hold = typecacheof(list(/obj/item/stack/sheet)) + STR.cant_hold = typecacheof(list(/obj/item/stack/sheet/mineral/sandstone, /obj/item/stack/sheet/mineral/wood)) + STR.max_combined_stack_amount = 300 // ----------------------------- // Sheet Snatcher (Cyborg) @@ -320,6 +236,10 @@ desc = "" capacity = 500//Borgs get more because >specialization +/obj/item/storage/bag/sheetsnatcher/borg/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage/concrete/stack) + STR.max_combined_stack_amount = 500 // ----------------------------- // Book bag @@ -330,14 +250,18 @@ desc = "A bag for books." icon = 'icons/obj/library.dmi' icon_state = "bookbag" - display_contents_with_number = 0 //This would look really stupid otherwise - storage_slots = 7 - max_combined_w_class = 21 - max_w_class = WEIGHT_CLASS_NORMAL w_class = WEIGHT_CLASS_BULKY //Bigger than a book because physics - can_hold = list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook) resistance_flags = FLAMMABLE +/obj/item/storage/bag/books/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 21 + STR.max_items = 7 + STR.display_numerical_stacking = FALSE + STR.can_hold = typecacheof(list(/obj/item/book, /obj/item/storage/book, /obj/item/spellbook)) + /* * Trays - Agouri */ @@ -353,14 +277,18 @@ w_class = WEIGHT_CLASS_BULKY flags_1 = CONDUCT_1 materials = list(MAT_METAL=3000) - preposition = "on" + +/obj/item/storage/bag/tray/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.insert_preposition = "on" /obj/item/storage/bag/tray/attack(mob/living/M, mob/living/user) - ..() + . = ..() // Drop all the things. All of them. var/list/obj/item/oldContents = contents.Copy() - quick_empty() - + GET_COMPONENT(STR, /datum/component/storage) + STR.quick_empty() // Make each item scatter a bit for(var/obj/item/I in oldContents) spawn() @@ -377,20 +305,20 @@ if(ishuman(M) || ismonkey(M)) if(prob(10)) M.Knockdown(40) + update_icon() -/obj/item/storage/bag/tray/proc/rebuild_overlays() +/obj/item/storage/bag/tray/update_icon() cut_overlays() for(var/obj/item/I in contents) add_overlay(mutable_appearance(I.icon, I.icon_state)) -/obj/item/storage/bag/tray/remove_from_storage(obj/item/W as obj, atom/new_location) - ..() - rebuild_overlays() - -/obj/item/storage/bag/tray/handle_item_insertion(obj/item/I, prevent_warning = 0) - add_overlay(mutable_appearance(I.icon, I.icon_state)) +/obj/item/storage/bag/tray/Entered() . = ..() + update_icon() +/obj/item/storage/bag/tray/Exited() + . = ..() + update_icon() /* * Chemistry bag @@ -401,12 +329,17 @@ icon = 'icons/obj/chemical.dmi' icon_state = "bag" desc = "A bag for storing pills, patches, and bottles." - storage_slots = 50 - max_combined_w_class = 200 w_class = WEIGHT_CLASS_TINY - can_hold = list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle) resistance_flags = FLAMMABLE +/obj/item/storage/bag/chemistry/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 200 + STR.max_items = 50 + STR.insert_preposition = "in" + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle)) + /* * Biowaste bag (mostly for xenobiologists) */ @@ -416,8 +349,13 @@ icon = 'icons/obj/chemical.dmi' icon_state = "biobag" desc = "A bag for the safe transportation and disposal of biowaste and other biological materials." - storage_slots = 25 - max_combined_w_class = 200 w_class = WEIGHT_CLASS_TINY - can_hold = list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube) resistance_flags = FLAMMABLE + +/obj/item/storage/bag/bio/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 200 + STR.max_items = 25 + STR.insert_preposition = "in" + STR.can_hold = typecacheof(list(/obj/item/slime_extract, /obj/item/reagent_containers/syringe, /obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle, /obj/item/reagent_containers/blood, /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/food/snacks/deadmouse, /obj/item/reagent_containers/food/snacks/monkeycube)) diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm index d0b3480f04..a4cd9cc739 100755 --- a/code/game/objects/items/storage/belt.dm +++ b/code/game/objects/items/storage/belt.dm @@ -32,7 +32,12 @@ desc = "Holds tools." icon_state = "utilitybelt" item_state = "utility" - can_hold = list( + content_overlays = TRUE + +/obj/item/storage/belt/ulility/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.can_hold = typecacheof(list( /obj/item/crowbar, /obj/item/screwdriver, /obj/item/weldingtool, @@ -49,8 +54,7 @@ /obj/item/clothing/gloves, /obj/item/holosign_creator, /obj/item/device/assembly/signaler - ) - content_overlays = TRUE + )) /obj/item/storage/belt/utility/chief name = "\improper Chief Engineer's toolbelt" //"the Chief Engineer's toolbelt", because "Chief Engineer's toolbelt" is not a proper noun @@ -68,7 +72,6 @@ new /obj/item/device/analyzer(src) //much roomier now that we've managed to remove two tools - /obj/item/storage/belt/utility/full/PopulateContents() new /obj/item/screwdriver(src) new /obj/item/wrench(src) @@ -106,16 +109,17 @@ new /obj/item/device/multitool(src) new /obj/item/stack/cable_coil(src, 30, "yellow") - - - /obj/item/storage/belt/medical name = "medical belt" desc = "Can hold various medical equipment." icon_state = "medicalbelt" item_state = "medical" - max_w_class = WEIGHT_CLASS_BULKY - can_hold = list( + +/obj/item/storage/belt/medical/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_BULKY + STR.can_hold = typecacheof(list( /obj/item/device/healthanalyzer, /obj/item/dnainjector, /obj/item/reagent_containers/dropper, @@ -156,23 +160,26 @@ /obj/item/storage/bag/bio, /obj/item/reagent_containers/blood, /obj/item/tank/internals/emergency_oxygen, - /obj/item/pinpointer/crew, /obj/item/gun/syringe/syndicate, /obj/item/implantcase, /obj/item/implant, /obj/item/implanter, - /obj/item/hypospray - ) - // CIT CHANGE added hypospray mk IIs to belt /obj/item/hypospray + /obj/item/pinpointer/crew + )) /obj/item/storage/belt/security name = "security belt" desc = "Can hold security gear like handcuffs and flashes." icon_state = "securitybelt" item_state = "security"//Could likely use a better one. - storage_slots = 5 - max_w_class = WEIGHT_CLASS_NORMAL //Because the baton wouldn't fit otherwise. - Neerti - can_hold = list( + content_overlays = TRUE + +/obj/item/storage/belt/security/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 5 + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.can_hold = typecacheof(list( /obj/item/melee/baton, /obj/item/melee/classic_baton, /obj/item/grenade, @@ -188,10 +195,8 @@ /obj/item/melee/classic_baton/telescopic, /obj/item/device/radio, /obj/item/clothing/gloves, - /obj/item/restraints/legcuffs/bola, - /obj/item/holosign_creator/security - ) - content_overlays = TRUE + /obj/item/restraints/legcuffs/bola + )) /obj/item/storage/belt/security/full/PopulateContents() new /obj/item/reagent_containers/spray/pepper(src) @@ -201,17 +206,20 @@ new /obj/item/melee/baton/loaded(src) update_icon() - /obj/item/storage/belt/mining name = "explorer's webbing" desc = "A versatile chest rig, cherished by miners and hunters alike." icon_state = "explorer1" item_state = "explorer1" - storage_slots = 6 w_class = WEIGHT_CLASS_BULKY - max_w_class = WEIGHT_CLASS_BULKY //Pickaxes are big. - max_combined_w_class = 20 //Not an issue with this whitelist, probably. - can_hold = list( + +/obj/item/storage/belt/mining/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 6 + STR.max_w_class = WEIGHT_CLASS_BULKY + STR.max_combined_w_class = 20 + STR.can_hold = typecacheof(list( /obj/item/crowbar, /obj/item/screwdriver, /obj/item/weldingtool, @@ -248,7 +256,7 @@ /obj/item/device/wormhole_jaunter, /obj/item/storage/bag/plants, /obj/item/stack/marker_beacon - ) + )) /obj/item/storage/belt/mining/vendor @@ -261,19 +269,27 @@ /obj/item/storage/belt/mining/primitive name = "hunter's belt" desc = "A versatile belt, woven from sinew." - storage_slots = 5 icon_state = "ebelt" item_state = "ebelt" +/obj/item/storage/belt/mining/primitive/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 5 + /obj/item/storage/belt/soulstone name = "soul stone belt" desc = "Designed for ease of access to the shards during a fight, as to not let a single enemy spirit slip away." icon_state = "soulstonebelt" item_state = "soulstonebelt" - storage_slots = 6 - can_hold = list( + +/obj/item/storage/belt/soulstone/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 6 + STR.can_hold = typecacheof(list( /obj/item/device/soulstone - ) + )) /obj/item/storage/belt/soulstone/full/PopulateContents() for(var/i in 1 to 6) @@ -289,8 +305,12 @@ icon_state = "championbelt" item_state = "champion" materials = list(MAT_GOLD=400) - storage_slots = 1 - can_hold = list( + +/obj/item/storage/belt/champion/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 1 + STR.can_hold = list( /obj/item/clothing/mask/luchador ) @@ -299,7 +319,11 @@ desc = "A set of tactical webbing worn by Syndicate boarding parties." icon_state = "militarywebbing" item_state = "militarywebbing" - max_w_class = WEIGHT_CLASS_SMALL + +/obj/item/storage/belt/military/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_SMALL /obj/item/storage/belt/military/abductor name = "agent belt" @@ -317,7 +341,6 @@ new /obj/item/device/multitool/abductor(src) new /obj/item/stack/cable_coil(src,30,"white") - /obj/item/storage/belt/military/army name = "army belt" desc = "A belt used by military forces." @@ -329,25 +352,34 @@ desc = "A tactical assault belt." icon_state = "assaultbelt" item_state = "security" - storage_slots = 6 + +/obj/item/storage/belt/military/assault/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 6 /obj/item/storage/belt/grenade name = "grenadier belt" desc = "A belt for holding grenades." icon_state = "grenadebeltnew" item_state = "security" - max_w_class = WEIGHT_CLASS_BULKY - display_contents_with_number = TRUE - storage_slots = 30 - max_combined_w_class = 60 //needs to be this high - can_hold = list( + +/obj/item/storage/belt/grenade/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 30 + STR.display_numerical_stacking = TRUE + STR.max_combined_w_class = 60 + STR.max_w_class = WEIGHT_CLASS_BULKY + STR.can_hold = typecacheof(list( /obj/item/grenade, /obj/item/screwdriver, /obj/item/lighter, /obj/item/device/multitool, /obj/item/reagent_containers/food/drinks/bottle/molotov, /obj/item/grenade/plastic/c4, - ) + )) + /obj/item/storage/belt/grenade/full/PopulateContents() new /obj/item/grenade/flashbang(src) new /obj/item/grenade/smokebomb(src) @@ -383,10 +415,14 @@ desc = "A belt designed to hold various rods of power. A veritable fanny pack of exotic magic." icon_state = "soulstonebelt" item_state = "soulstonebelt" - storage_slots = 6 - can_hold = list( + +/obj/item/storage/belt/wands/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 6 + STR.can_hold = typecacheof(list( /obj/item/gun/magic/wand - ) + )) /obj/item/storage/belt/wands/full/PopulateContents() new /obj/item/gun/magic/wand/death(src) @@ -405,9 +441,13 @@ desc = "A belt used to hold most janitorial supplies." icon_state = "janibelt" item_state = "janibelt" - storage_slots = 6 - max_w_class = WEIGHT_CLASS_BULKY // Set to this so the light replacer can fit. - can_hold = list( + +/obj/item/storage/belt/janitor/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 6 + STR.max_w_class = WEIGHT_CLASS_BULKY // Set to this so the light replacer can fit. + STR.can_hold = typecacheof(list( /obj/item/grenade/chem_grenade, /obj/item/device/lightreplacer, /obj/item/device/flashlight, @@ -418,32 +458,40 @@ /obj/item/clothing/gloves, /obj/item/melee/flyswatter, /obj/item/device/assembly/mousetrap - ) + )) /obj/item/storage/belt/bandolier name = "bandolier" desc = "A bandolier for holding shotgun ammunition." icon_state = "bandolier" item_state = "bandolier" - storage_slots = 18 - display_contents_with_number = TRUE - can_hold = list( + +/obj/item/storage/belt/bandolier/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 18 + STR.display_numerical_stacking = TRUE + STR.can_hold = typecacheof(list( /obj/item/ammo_casing/shotgun - ) + )) /obj/item/storage/belt/holster name = "shoulder holster" desc = "A holster to carry a handgun and ammo. WARNING: Badasses only." icon_state = "holster" item_state = "holster" - storage_slots = 3 - max_w_class = WEIGHT_CLASS_NORMAL - can_hold = list( + alternate_worn_layer = UNDER_SUIT_LAYER + +/obj/item/storage/belt/holster/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 3 + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.can_hold = typecacheof(list( /obj/item/gun/ballistic/automatic/pistol, /obj/item/gun/ballistic/revolver, /obj/item/ammo_box, - ) - alternate_worn_layer = UNDER_SUIT_LAYER + )) /obj/item/storage/belt/holster/full/PopulateContents() new /obj/item/gun/ballistic/revolver/detective(src) @@ -455,8 +503,12 @@ desc = "A dorky fannypack for keeping small items in." icon_state = "fannypack_leather" item_state = "fannypack_leather" - storage_slots = 3 - max_w_class = WEIGHT_CLASS_SMALL + +/obj/item/storage/belt/fannypack/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 3 + STR.max_w_class = WEIGHT_CLASS_SMALL /obj/item/storage/belt/fannypack/black name = "black fannypack" @@ -513,26 +565,29 @@ desc = "An ornate sheath designed to hold an officer's blade." icon_state = "sheath" item_state = "sheath" - storage_slots = 1 - rustle_jimmies = FALSE w_class = WEIGHT_CLASS_BULKY - max_w_class = WEIGHT_CLASS_BULKY - can_hold = list( + +/obj/item/storage/belt/sabre/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 1 + STR.rustle_sound = FALSE + STR.max_w_class = WEIGHT_CLASS_BULKY + STR.can_hold = typecacheof(list( /obj/item/melee/sabre - ) + )) /obj/item/storage/belt/sabre/examine(mob/user) ..() - if(contents.len) + if(length(contents)) to_chat(user, "Alt-click it to quickly draw the blade.") /obj/item/storage/belt/sabre/AltClick(mob/user) if(!iscarbon(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user))) return - if(contents.len) + if(length(contents)) var/obj/item/I = contents[1] - user.visible_message("[user] takes [I] out of [src].", "You take [I] out of [src].",\ - ) + user.visible_message("[user] takes [I] out of [src].", "You take [I] out of [src].") user.put_in_hands(I) update_icon() else @@ -549,7 +604,6 @@ L.regenerate_icons() ..() - /obj/item/storage/belt/sabre/PopulateContents() new /obj/item/melee/sabre(src) update_icon() diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm index 10b28e12f6..41f2a4bf47 100644 --- a/code/game/objects/items/storage/book.dm +++ b/code/game/objects/items/storage/book.dm @@ -5,11 +5,15 @@ icon_state ="book" throw_speed = 2 throw_range = 5 - storage_slots = 1 w_class = WEIGHT_CLASS_NORMAL resistance_flags = FLAMMABLE var/title = "book" +/obj/item/storage/book/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 1 + /obj/item/storage/book/attack_self(mob/user) to_chat(user, "The pages of [title] have been cut out!") @@ -205,8 +209,6 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible", attack_verb = list("attacked", "burned", "blessed", "damned", "scorched") var/uses = 1 - - /obj/item/storage/book/bible/syndicate/attack_self(mob/living/carbon/human/H) if (uses) H.mind.isholy = TRUE diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm index 90251832bf..d244e512c3 100644 --- a/code/game/objects/items/storage/boxes.dm +++ b/code/game/objects/items/storage/boxes.dm @@ -64,9 +64,6 @@ if(!ispath(foldable)) return - //Close any open UI windows first - close_all() - to_chat(user, "You fold [src] flat.") var/obj/item/I = new foldable qdel(src) @@ -360,7 +357,11 @@ desc = "Instructions: Heat in microwave. Product will cool if not eaten within seven minutes." icon_state = "donkpocketbox" illustration=null - can_hold = list(/obj/item/reagent_containers/food/snacks/donkpocket) + +/obj/item/storage/box/donkpockets/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donkpocket)) /obj/item/storage/box/donkpockets/PopulateContents() for(var/i in 1 to 6) @@ -370,10 +371,14 @@ name = "monkey cube box" desc = "Drymate brand monkey cubes. Just add water!" icon_state = "monkeycubebox" - storage_slots = 7 - can_hold = list(/obj/item/reagent_containers/food/snacks/monkeycube) illustration = null +/obj/item/storage/box/monkeycubes/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 7 + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/monkeycube)) + /obj/item/storage/box/monkeycubes/PopulateContents() for(var/i in 1 to 5) new /obj/item/reagent_containers/food/snacks/monkeycube(src) @@ -522,12 +527,15 @@ desc = "Eight wrappers of fun! Ages 8 and up. Not suitable for children." icon = 'icons/obj/toy.dmi' icon_state = "spbox" - storage_slots = 8 - can_hold = list(/obj/item/toy/snappop) + +/obj/item/storage/box/snappops/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.can_hold = typecacheof(list(/obj/item/toy/snappop)) + STR.max_items = 8 /obj/item/storage/box/snappops/PopulateContents() - for(var/i in 1 to storage_slots) - new /obj/item/toy/snappop(src) + SendSignal(COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/toy/snappop) /obj/item/storage/box/matches name = "matchbox" @@ -535,14 +543,17 @@ icon = 'icons/obj/cigarettes.dmi' icon_state = "matchbox" item_state = "zippo" - storage_slots = 10 w_class = WEIGHT_CLASS_TINY slot_flags = SLOT_BELT - can_hold = list(/obj/item/match) + +/obj/item/storage/box/matches/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 10 + STR.can_hold = typecacheof(list(/obj/item/match)) /obj/item/storage/box/matches/PopulateContents() - for(var/i in 1 to storage_slots) - new /obj/item/match(src) + SendSignal(COMSIG_TRY_STORAGE_FILL_TYPE, /obj/item/match) /obj/item/storage/box/matches/attackby(obj/item/match/W as obj, mob/user as mob, params) if(istype(W, /obj/item/match)) @@ -557,10 +568,14 @@ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' foldable = /obj/item/stack/sheet/cardboard //BubbleWrap - storage_slots=21 - can_hold = list(/obj/item/light/tube, /obj/item/light/bulb) - max_combined_w_class = 21 - use_to_pickup = 1 // for picking up broken bulbs, not that most people will try + +/obj/item/storage/box/lights/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 21 + STR.can_hold = typecacheof(list(/obj/item/light/tube, /obj/item/light/bulb)) + STR.max_combined_w_class = 21 + STR.click_gather = TRUE /obj/item/storage/box/lights/bulbs/PopulateContents() for(var/i in 1 to 21) diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm index 0703eba47a..5fdf94c1f3 100644 --- a/code/game/objects/items/storage/briefcase.dm +++ b/code/game/objects/items/storage/briefcase.dm @@ -10,13 +10,17 @@ 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") resistance_flags = FLAMMABLE max_integrity = 150 var/folder_path = /obj/item/folder //this is the path of the folder that gets spawned in New() +/obj/item/storage/briefcase/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 21 + /obj/item/storage/briefcase/PopulateContents() new /obj/item/pen(src) var/obj/item/folder/folder = new folder_path(src) @@ -31,20 +35,8 @@ ..() /obj/item/storage/briefcase/sniperbundle - name = "briefcase" desc = "It's label reads genuine hardened Captain leather, but suspiciously has no other tags or branding. Smells like L'Air du Temps." - icon_state = "briefcase" - flags_1 = CONDUCT_1 force = 10 - 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") - resistance_flags = FLAMMABLE - max_integrity = 150 /obj/item/storage/briefcase/sniperbundle/PopulateContents() ..() // in case you need any paperwork done after your rampage diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm index b574855f10..d669431be5 100644 --- a/code/game/objects/items/storage/fancy.dm +++ b/code/game/objects/items/storage/fancy.dm @@ -25,7 +25,8 @@ var/fancy_open = FALSE /obj/item/storage/fancy/PopulateContents() - for(var/i = 1 to storage_slots) + GET_COMPONENT(STR, /datum/component/storage) + for(var/i = 1 to STR.max_items) new spawn_type(src) /obj/item/storage/fancy/update_icon() @@ -37,7 +38,7 @@ /obj/item/storage/fancy/examine(mob/user) ..() if(fancy_open) - if(contents.len == 1) + if(length(contents) == 1) to_chat(user, "There is one [icon_type] left.") else to_chat(user, "There are [contents.len <= 0 ? "no" : "[contents.len]"] [icon_type]s left.") @@ -45,20 +46,17 @@ /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) +/obj/item/storage/fancy/Exited() + . = ..() fancy_open = TRUE - return ..() + update_icon() -/obj/item/storage/fancy/remove_from_storage(obj/item/W, atom/new_location, burn = 0) +/obj/item/storage/fancy/Entered() + . = ..() fancy_open = TRUE - return ..() + update_icon() /* * Donut Box @@ -69,11 +67,15 @@ 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 +/obj/item/storage/fancy/donut_box/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 6 + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/donut)) + /* * Egg Box */ @@ -87,10 +89,14 @@ righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi' name = "egg box" desc = "A carton for containing eggs." - storage_slots = 12 - can_hold = list(/obj/item/reagent_containers/food/snacks/egg) spawn_type = /obj/item/reagent_containers/food/snacks/egg +/obj/item/storage/fancy/egg_box/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 12 + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/egg)) + /* * Candle Box */ @@ -102,12 +108,16 @@ 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 5 + /obj/item/storage/fancy/candle_box/attack_self(mob_user) return @@ -123,11 +133,15 @@ 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 6 + STR.can_hold = typecacheof(list(/obj/item/clothing/mask/cigarette, /obj/item/lighter)) + /obj/item/storage/fancy/cigarettes/examine(mob/user) ..() to_chat(user, "Alt-click to extract contents.") @@ -137,7 +151,7 @@ return var/obj/item/clothing/mask/cigarette/W = locate(/obj/item/clothing/mask/cigarette) in contents if(W && contents.len > 0) - remove_from_storage(W, user) + SendSignal(COMSIG_TRY_STORAGE_TAKE, W, user) user.put_in_hands(W) contents -= W to_chat(user, "You take a [icon_type] out of the pack.") @@ -174,7 +188,7 @@ if(cig) if(M == user && contents.len > 0 && !user.wear_mask) var/obj/item/clothing/mask/cigarette/W = cig - remove_from_storage(W, M) + SendSignal(COMSIG_TRY_STORAGE_TAKE, 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.") @@ -243,11 +257,15 @@ 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 10 + STR.can_hold = typecacheof(list(/obj/item/rollingpaper)) + /obj/item/storage/fancy/rollingpapers/update_icon() cut_overlays() if(!contents.len) @@ -263,11 +281,15 @@ 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 5 + STR.can_hold = typecacheof(list(/obj/item/clothing/mask/cigarette/cigar)) + /obj/item/storage/fancy/cigarettes/cigars/update_icon() cut_overlays() if(fancy_open) @@ -302,6 +324,10 @@ icon_type = "chocolate" lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi' righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi' - storage_slots = 8 - can_hold = list(/obj/item/reagent_containers/food/snacks/tinychocolate) spawn_type = /obj/item/reagent_containers/food/snacks/tinychocolate + +/obj/item/storage/fancy/heart_box/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 8 + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/food/snacks/tinychocolate)) diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm index 335ba2b211..d5548ee95c 100644 --- a/code/game/objects/items/storage/firstaid.dm +++ b/code/game/objects/items/storage/firstaid.dm @@ -16,7 +16,7 @@ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' throw_speed = 3 throw_range = 7 - var/empty = 0 + var/empty = FALSE /obj/item/storage/firstaid/regular icon_state = "firstaid" @@ -41,7 +41,6 @@ icon_state = "firstaid" desc = "A first aid kit with the ability to heal common types of injuries." - /obj/item/storage/firstaid/ancient/PopulateContents() if(empty) return @@ -142,7 +141,11 @@ name = "combat medical kit" desc = "I hope you've got insurance." icon_state = "bezerk" - max_w_class = WEIGHT_CLASS_NORMAL + +/obj/item/storage/firstaid/tactical/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL /obj/item/storage/firstaid/tactical/PopulateContents() if(empty) @@ -155,10 +158,10 @@ new /obj/item/reagent_containers/syringe/lethal/choral(src) new /obj/item/clothing/glasses/hud/health/night(src) - /* * Pill Bottles */ + /obj/item/storage/pill_bottle name = "pill bottle" desc = "It's an airtight container for storing medication." @@ -168,24 +171,13 @@ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi' w_class = WEIGHT_CLASS_SMALL - can_hold = list(/obj/item/reagent_containers/pill, /obj/item/dice) - allow_quick_gather = 1 - use_to_pickup = 1 -/obj/item/storage/pill_bottle/MouseDrop(obj/over_object) //Quick pillbottle fix. -Agouri - - if(ishuman(usr) || ismonkey(usr)) //Can monkeys even place items in the pocket slots? Leaving this in just in case~ - var/mob/M = usr - if(!istype(over_object, /obj/screen) || !Adjacent(M)) - return ..() - if(!M.incapacitated() && istype(over_object, /obj/screen/inventory/hand)) - var/obj/screen/inventory/hand/H = over_object - if(M.putItemFromInventoryInHandIfPossible(src, H.held_index)) - add_fingerprint(usr) - if(over_object == usr && in_range(src, usr) || usr.contents.Find(src)) - if(usr.s_active) - usr.s_active.close(usr) - src.show_to(usr) +/obj/item/storage/pill_bottle/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.allow_quick_gather = TRUE + STR.click_gather = TRUE + STR.can_hold = typecacheof(list(/obj/item/reagent_containers/pill, /obj/item/dice)) /obj/item/storage/pill_bottle/suicide_act(mob/user) user.visible_message("[user] is trying to get the cap off [src]! It looks like [user.p_theyre()] trying to commit suicide!") diff --git a/code/game/objects/items/storage/internal.dm b/code/game/objects/items/storage/internal.dm deleted file mode 100644 index 2c44f3b306..0000000000 --- a/code/game/objects/items/storage/internal.dm +++ /dev/null @@ -1,88 +0,0 @@ -/obj/item/storage/internal - storage_slots = 2 - max_w_class = WEIGHT_CLASS_SMALL - max_combined_w_class = 50 // Limited by slots, not combined weight class - w_class = WEIGHT_CLASS_BULKY - rustle_jimmies = FALSE - -/obj/item/storage/internal/Adjacent(A) - if(loc) - return loc.Adjacent(A) - -/obj/item/storage/internal/pocket - var/priority = TRUE - // TRUE if opens when clicked, like a backpack. - // FALSE if opens only when dragged on mob's icon (hidden pocket) - var/quickdraw = FALSE - // TRUE if you can quickdraw items from it with alt-click. - -/obj/item/storage/internal/pocket/New() - ..() - if(loc) - name = loc.name - -/obj/item/storage/internal/pocket/handle_item_insertion(obj/item/W, prevent_warning = 0, mob/user) - . = ..() - if(. && silent && !prevent_warning) - if(quickdraw) - to_chat(user, "You discreetly slip [W] into [src]. Alt-click [src] to remove it.") - else - to_chat(user, "You discreetly slip [W] into [src].") - -/obj/item/storage/internal/pocket/big - max_w_class = WEIGHT_CLASS_NORMAL - -/obj/item/storage/internal/pocket/small - storage_slots = 1 - -/obj/item/storage/internal/pocket/tiny - storage_slots = 1 - max_w_class = WEIGHT_CLASS_TINY - priority = FALSE - -/obj/item/storage/internal/pocket/shoes - can_hold = list( - /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, - /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, - /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper, - /obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini, - /obj/item/device/firing_pin - ) - //can hold both regular pens and energy daggers. made for your every-day tactical curators/murderers. - priority = FALSE - quickdraw = TRUE - silent = TRUE - - -/obj/item/storage/internal/pocket/shoes/clown - can_hold = list( - /obj/item/kitchen/knife, /obj/item/switchblade, /obj/item/pen, - /obj/item/scalpel, /obj/item/reagent_containers/syringe, /obj/item/dnainjector, - /obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/dropper, - /obj/item/implanter, /obj/item/screwdriver, /obj/item/weldingtool/mini, - /obj/item/device/firing_pin, /obj/item/bikehorn) - -/obj/item/storage/internal/pocket/small/detective - priority = TRUE // so the detectives would discover pockets in their hats - -/obj/item/storage/internal/pocket/small/detective/PopulateContents() - new /obj/item/reagent_containers/food/drinks/flask/det(src) - -/obj/item/storage/internal/pocket/pocketprotector - storage_slots = 3 - max_w_class = WEIGHT_CLASS_TINY - can_hold = list( //Same items as a PDA - /obj/item/pen, - /obj/item/toy/crayon, - /obj/item/lipstick, - /obj/item/device/flashlight/pen, - /obj/item/clothing/mask/cigarette) - -/obj/item/storage/internal/pocket/pocketprotector/cosmetology/PopulateContents() - for(var/i in 1 to 3) - new /obj/item/lipstick/random(src) - -/obj/item/storage/internal/pocket/pocketprotector/full/PopulateContents() - new /obj/item/pen/red(src) - new /obj/item/pen(src) - new /obj/item/pen/blue(src) diff --git a/code/game/objects/items/storage/lockbox.dm b/code/game/objects/items/storage/lockbox.dm index 51a0d476c3..3f8c3b24e7 100644 --- a/code/game/objects/items/storage/lockbox.dm +++ b/code/game/objects/items/storage/lockbox.dm @@ -6,29 +6,33 @@ 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 14 + STR.max_items = 4 /obj/item/storage/lockbox/attackby(obj/item/W, mob/user, params) + var/locked = SendSignal(COMSIG_IS_STORAGE_LOCKED) if(W.GetID()) if(broken) to_chat(user, "It appears to be broken.") return if(allowed(user)) - locked = !locked + SendSignal(COMSIG_TRY_STORAGE_SET_LOCKSTATE, !locked) + locked = SendSignal(COMSIG_IS_STORAGE_LOCKED) if(locked) icon_state = icon_locked to_chat(user, "You lock the [src.name]!") - close_all() + SendSignal(COMSIG_TRY_STORAGE_HIDE_ALL) return else icon_state = icon_closed @@ -42,51 +46,25 @@ 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 + SendSignal(COMSIG_TRY_STORAGE_SET_LOCKSTATE, 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) +/obj/item/storage/lockbox/Entered() + . = ..() open = TRUE update_icon() - return ..() -/obj/item/storage/lockbox/remove_from_storage(obj/item/W, atom/new_location, burn = 0) + +/obj/item/storage/lockbox/Exited() + . = ..() open = TRUE update_icon() - return ..() /obj/item/storage/lockbox/loyalty name = "lockbox of mindshield implants" @@ -97,7 +75,6 @@ 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." @@ -114,23 +91,28 @@ 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_SMALL + STR.max_items = 10 + STR.max_combined_w_class = 20 + STR.can_hold = typecacheof(list(/obj/item/clothing/accessory/medal)) /obj/item/storage/lockbox/medal/examine(mob/user) ..() + var/locked = SendSignal(COMSIG_IS_STORAGE_LOCKED) if(!locked) to_chat(user, "Alt-click to [open ? "close":"open"] it.") /obj/item/storage/lockbox/medal/AltClick(mob/user) if(user.canUseTopic(src, BE_CLOSE)) - if(!locked) + if(!SendSignal(COMSIG_IS_STORAGE_LOCKED)) open = (open ? FALSE : TRUE) update_icon() ..() @@ -148,6 +130,7 @@ /obj/item/storage/lockbox/medal/update_icon() cut_overlays() + var/locked = SendSignal(COMSIG_IS_STORAGE_LOCKED) if(locked) icon_state = "medalbox+l" open = FALSE diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index 1a0474b94d..73e178af3f 100644 --- a/code/game/objects/items/storage/secure.dm +++ b/code/game/objects/items/storage/secure.dm @@ -15,7 +15,6 @@ 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 @@ -23,16 +22,20 @@ var/l_hacking = 0 var/open = FALSE w_class = WEIGHT_CLASS_NORMAL - max_w_class = WEIGHT_CLASS_SMALL - max_combined_w_class = 14 desc = "This shouldn't exist. If it does, create an issue report." +/obj/item/storage/secure/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_SMALL + STR.max_combined_w_class = 14 + /obj/item/storage/secure/examine(mob/user) ..() to_chat(user, text("The service panel is currently [open ? "unscrewed" : "screwed shut"].")) /obj/item/storage/secure/attackby(obj/item/W, mob/user, params) - if(locked) + if(SendSignal(COMSIG_IS_STORAGE_LOCKED)) if (istype(W, /obj/item/screwdriver)) if (W.use_tool(src, user, 20)) open =! open @@ -41,15 +44,15 @@ if (istype(W, /obj/item/wirecutters)) to_chat(user, "[src] is protected from this sort of tampering, yet it appears the internal memory wires can still be pulsed.") if ((istype(W, /obj/item/device/multitool)) && (!l_hacking)) - if(src.open == 1) + if(open == 1) to_chat(user, "Now attempting to reset internal memory, please hold.") - src.l_hacking = 1 + l_hacking = 1 if (W.use_tool(src, user, 400)) to_chat(user, "Internal memory reset - lock has been disengaged.") - src.l_set = 0 - src.l_hacking = 0 + l_set = 0 + l_hacking = 0 else - src.l_hacking = 0 + l_hacking = 0 else to_chat(user, "You must unscrew the service panel before you can pulse the wiring.") return @@ -60,23 +63,17 @@ // -> 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) + var/locked = SendSignal(COMSIG_IS_STORAGE_LOCKED) user.set_machine(src) - var/dat = text("[]
\n\nLock Status: []",src, (src.locked ? "LOCKED" : "UNLOCKED")) + var/dat = text("[]
\n\nLock Status: []",src, (locked ? "LOCKED" : "UNLOCKED")) var/message = "Code" - if ((src.l_set == 0) && (!src.l_setshort)) + if ((l_set == 0) && (!l_setshort)) dat += text("

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

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


\n>[]
\n1-2-3
\n4-5-6
\n7-8-9
\nR-0-E
\n
", message) user << browse(dat, "window=caselock;size=300x280") @@ -87,44 +84,33 @@ 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 + if ((l_set == 0) && (length(code) == 5) && (!l_setshort) && (code != "ERROR")) + l_code = code + l_set = 1 + else if ((code == l_code) && (l_set == 1)) + SendSignal(COMSIG_TRY_STORAGE_SET_LOCKSTATE, FALSE) cut_overlays() add_overlay(icon_opened) - src.code = null + code = null else - src.code = "ERROR" + code = "ERROR" else - if ((href_list["type"] == "R") && (!src.l_setshort)) - src.locked = TRUE + if ((href_list["type"] == "R") && (!l_setshort)) + SendSignal(COMSIG_TRY_STORAGE_SET_LOCKSTATE, TRUE) cut_overlays() - src.code = null - src.close(usr) + code = null + SendSignal(COMSIG_TRY_STORAGE_HIDE_FROM, 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)) + code += text("[]", sanitize_text(href_list["type"])) + if (length(code) > 5) + code = "ERROR" + add_fingerprint(usr) + for(var/mob/M in viewers(1, loc)) if ((M.client && M.machine == src)) - src.attack_self(M) + 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 @@ -142,20 +128,17 @@ 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 - ..() +/obj/item/storage/secure/briefcase/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 21 + STR.max_w_class = WEIGHT_CLASS_NORMAL //Syndie variant of Secure Briefcase. Contains space cash, slightly more robust. /obj/item/storage/secure/briefcase/syndie @@ -163,7 +146,8 @@ /obj/item/storage/secure/briefcase/syndie/PopulateContents() ..() - for(var/i = 0, i < storage_slots - 2, i++) + GET_COMPONENT(STR, /datum/component/storage) + for(var/i = 0, i < STR.max_items - 2, i++) new /obj/item/stack/spacecash/c1000(src) @@ -181,16 +165,23 @@ desc = "Excellent for securing things away from grubby hands." 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/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.cant_hold = typecacheof(list(/obj/item/storage/secure/briefcase)) + STR.max_w_class = 8 //?? /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) + . = ..() + if(.) + return return attack_self(user) /obj/item/storage/secure/safe/HoS diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm index ff1c1331e2..7c2694016b 100644 --- a/code/game/objects/items/storage/storage.dm +++ b/code/game/objects/items/storage/storage.dm @@ -1,583 +1,23 @@ -// 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 (ismecha(M.loc)) // 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) - + var/component_type = /datum/component/storage/concrete /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 +/obj/item/storage/Initialize() + . = ..() + PopulateContents() -//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))) - stoplag(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) - if(QDELETED(O)) - continue - 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) - if(QDELETED(O)) - continue - 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) - if(QDELETED(I)) - continue - 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/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 new_location target, if that is null it's being deleted -/obj/item/storage/proc/remove_from_storage(obj/item/W, atom/new_location) - if(!istype(W)) - return 0 - - //Cache this as it should be reusable down the bottom, will not apply if anyone adds a sleep to dropped - //or moving objects, things that should never happen - var/list/seeing_mobs = can_see_contents() - for(var/mob/M in seeing_mobs) - M.client.screen -= W - - if(ismob(loc)) - var/mob/M = loc - W.dropped(M) - - - if(new_location) - W.forceMove(new_location) - //Reset the items values - W.layer = initial(W.layer) - W.plane = initial(W.plane) - W.mouse_opacity = initial(W.mouse_opacity) - if(W.maptext) - W.maptext = "" - //We don't want to call this if the item is being destroyed - W.on_exit_storage(src) - - else - //Being destroyed, just move to nullspace now (so it's not in contents for the icon update) - W.moveToNullspace() - - - for(var/mob/M in seeing_mobs) - orient2hud(M) - show_to(M) - - update_icon() - 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)) - return 1 - - handle_item_insertion(W, 0 , user) +/obj/item/storage/ComponentInitialize() + AddComponent(component_type) /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))) - stoplag(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) diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index 74c559117f..bea6b6de47 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -109,10 +109,14 @@ name = "suspicious looking toolbox" icon_state = "syndicate" item_state = "toolbox_syndi" - silent = 1 force = 15 throwforce = 18 +/obj/item/storage/toolbox/syndicate/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.silent = TRUE + /obj/item/storage/toolbox/syndicate/PopulateContents() new /obj/item/screwdriver/nuke(src) new /obj/item/wrench(src) @@ -145,12 +149,16 @@ has_latches = FALSE resistance_flags = FIRE_PROOF | ACID_PROOF w_class = WEIGHT_CLASS_HUGE - max_w_class = WEIGHT_CLASS_NORMAL - max_combined_w_class = 28 - storage_slots = 28 attack_verb = list("robusted", "crushed", "smashed") var/fabricator_type = /obj/item/clockwork/replica_fabricator/scarab +/obj/item/storage/toolbox/brass/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.max_combined_w_class = 28 + STR.max_items = 28 + /obj/item/storage/toolbox/brass/prefilled/PopulateContents() new fabricator_type(src) new /obj/item/screwdriver/brass(src) @@ -180,10 +188,14 @@ desc = "A toolbox painted bright green. Why anyone would store art supplies in a toolbox is beyond you, but it has plenty of extra space." icon_state = "green" item_state = "artistic_toolbox" - max_combined_w_class = 20 - storage_slots = 10 w_class = WEIGHT_CLASS_GIGANTIC //Holds more than a regular toolbox! +/obj/item/storage/toolbox/artistic/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_combined_w_class = 20 + STR.max_items = 10 + /obj/item/storage/toolbox/artistic/PopulateContents() new/obj/item/storage/crayons(src) new/obj/item/crowbar(src) diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index 62aebeda12..6c4d16f994 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -192,8 +192,12 @@ /obj/item/storage/box/syndie_kit/space name = "boxed space suit and helmet" - can_hold = list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate) - max_w_class = WEIGHT_CLASS_NORMAL + +/obj/item/storage/box/syndie_kit/space/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_w_class = WEIGHT_CLASS_NORMAL + STR.can_hold = typecacheof(list(/obj/item/clothing/suit/space/syndicate, /obj/item/clothing/head/helmet/space/syndicate)) /obj/item/storage/box/syndie_kit/space/PopulateContents() new /obj/item/clothing/suit/space/syndicate/black/red(src) // Black and red is so in right now @@ -212,7 +216,11 @@ /obj/item/storage/box/syndie_kit/chemical name = "boxed chemical kit" - storage_slots = 14 + +/obj/item/storage/box/syndie_kit/chemical/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 14 /obj/item/storage/box/syndie_kit/chemical/PopulateContents() new /obj/item/reagent_containers/glass/bottle/polonium(src) diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm index 885dbc3830..fa649fddc6 100644 --- a/code/game/objects/items/storage/wallets.dm +++ b/code/game/objects/items/storage/wallets.dm @@ -1,11 +1,19 @@ /obj/item/storage/wallet name = "wallet" desc = "It can hold a few small and personal things." - storage_slots = 4 icon_state = "wallet" w_class = WEIGHT_CLASS_SMALL resistance_flags = FLAMMABLE - can_hold = list( + slot_flags = SLOT_ID + + var/obj/item/card/id/front_id = null + var/list/combined_access + +/obj/item/storage/wallet/ComponentInitialize() + . = ..() + GET_COMPONENT(STR, /datum/component/storage) + STR.max_items = 4 + STR.can_hold = typecacheof(list( /obj/item/stack/spacecash, /obj/item/card, /obj/item/clothing/mask/cigarette, @@ -26,48 +34,39 @@ /obj/item/reagent_containers/dropper, /obj/item/reagent_containers/syringe, /obj/item/screwdriver, - /obj/item/stamp) - slot_flags = SLOT_ID + /obj/item/stamp)) - var/obj/item/card/id/front_id = null - var/list/combined_access = list() - - -/obj/item/storage/wallet/remove_from_storage(obj/item/W, atom/new_location) - . = ..(W, new_location) - if(.) - if(istype(W, /obj/item/card/id)) - if(W == front_id) - front_id = null - refreshID() - update_icon() +/obj/item/storage/wallet/Exited(atom/movable/AM) + . = ..() + refreshID() /obj/item/storage/wallet/proc/refreshID() - combined_access.Cut() + if(!(front_id in src)) + front_id = null for(var/obj/item/card/id/I in contents) + LAZYINITLIST(combined_access) + LAZYCLEARLIST(combined_access) if(!front_id) front_id = I - update_icon() combined_access |= I.access + update_icon() -/obj/item/storage/wallet/handle_item_insertion(obj/item/W, prevent_warning = 0) +/obj/item/storage/wallet/Entered(atom/movable/AM) . = ..() - if(.) - if(istype(W, /obj/item/card/id)) - refreshID() + refreshID() /obj/item/storage/wallet/update_icon() - icon_state = "wallet" + var/new_state = "wallet" if(front_id) - icon_state = "wallet_[front_id.icon_state]" - - + new_state = "wallet_[front_id.icon_state]" + if(new_state != icon_state) //avoid so many icon state changes. + icon_state = new_state /obj/item/storage/wallet/GetID() return front_id /obj/item/storage/wallet/GetAccess() - if(combined_access.len) + if(LAZYLEN(combined_access)) return combined_access else return ..() diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm index 6bae2af476..dc496187bc 100644 --- a/code/game/objects/items/tools/weldingtool.dm +++ b/code/game/objects/items/tools/weldingtool.dm @@ -28,6 +28,7 @@ var/change_icons = 1 var/can_off_process = 0 var/light_intensity = 2 //how powerful the emitted light is when used. + var/progress_flash_divisor = 10 var/burned_fuel_for = 0 //when fuel was last removed heat = 3800 tool_behaviour = TOOL_WELDER @@ -234,6 +235,16 @@ if(. && user) user.flash_act(light_intensity) +// Flash the user during welding progress +/obj/item/weldingtool/tool_check_callback(mob/living/user, amount, datum/callback/extra_checks) + . = ..() + if(. && user) + if (progress_flash_divisor == 0) + user.flash_act(min(light_intensity,1)) + progress_flash_divisor = initial(progress_flash_divisor) + else + progress_flash_divisor-- + // If welding tool ran out of fuel during a construction task, construction fails. /obj/item/weldingtool/tool_use_check(mob/living/user, amount) if(!isOn() || !check_fuel()) @@ -358,4 +369,4 @@ nextrefueltick = world.time + 10 reagents.add_reagent("welding_fuel", 1) -#undef WELDER_FUEL_BURN_INTERVAL \ No newline at end of file +#undef WELDER_FUEL_BURN_INTERVAL diff --git a/code/game/objects/structures/crates_lockers/crates/bins.dm b/code/game/objects/structures/crates_lockers/crates/bins.dm index 5767995712..9f14fff8d0 100644 --- a/code/game/objects/structures/crates_lockers/crates/bins.dm +++ b/code/game/objects/structures/crates_lockers/crates/bins.dm @@ -27,8 +27,7 @@ var/obj/item/storage/bag/trash/T = W to_chat(user, "You fill the bag.") for(var/obj/item/O in src) - if(T.can_be_inserted(O, 1)) - O.forceMove(T) + T.SendSignal(COMSIG_TRY_STORAGE_INSERT, O, user, TRUE) T.update_icon() do_animate() return TRUE diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm index 8d7d946647..19103c71ec 100644 --- a/code/game/objects/structures/fence.dm +++ b/code/game/objects/structures/fence.dm @@ -155,7 +155,6 @@ #undef CLIMB_TIME #undef NO_HOLE -#undef SMALL_HOLE #undef MEDIUM_HOLE #undef LARGE_HOLE #undef MAX_HOLE_SIZE \ No newline at end of file diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index cceed2ef17..c20168f52c 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -135,11 +135,7 @@ if(istype(I, /obj/item/storage/bag/tray)) var/obj/item/storage/bag/tray/T = I if(T.contents.len > 0) // If the tray isn't empty - var/list/obj/item/oldContents = T.contents.Copy() - T.quick_empty() - for(var/obj/item/C in oldContents) - C.forceMove(drop_location()) - + I.SendSignal(COMSIG_TRY_STORAGE_QUICK_EMPTY, drop_location()) user.visible_message("[user] empties [I] on [src].") return // If the tray IS empty, continue on (tray will be placed on the table like other items) diff --git a/code/game/turfs/baseturf_skipover.dm b/code/game/turfs/baseturf_skipover.dm new file mode 100644 index 0000000000..644714f8ed --- /dev/null +++ b/code/game/turfs/baseturf_skipover.dm @@ -0,0 +1,13 @@ +// This is a typepath to just sit in baseturfs and act as a marker for other things. +/turf/baseturf_skipover + name = "Baseturf skipover placeholder" + desc = "This shouldn't exist" + +/turf/baseturf_skipover/Initialize() + . = ..() + stack_trace("[src]([type]) was instanced which should never happen. Changing into the next baseturf down...") + ScrapeAway() + +/turf/baseturf_skipover/shuttle + name = "Shuttle baseturf skipover" + desc = "Acts as the bottom of the shuttle, if this isn't here the shuttle floor is broken through." \ No newline at end of file diff --git a/code/game/turfs/ChangeTurf.dm b/code/game/turfs/change_turf.dm similarity index 81% rename from code/game/turfs/ChangeTurf.dm rename to code/game/turfs/change_turf.dm index 7394592c08..253ceb29ac 100644 --- a/code/game/turfs/ChangeTurf.dm +++ b/code/game/turfs/change_turf.dm @@ -12,11 +12,11 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( var/thing = allowed_contents[i] qdel(thing, force=TRUE) - var/turf/newT = ChangeTurf(turf_type, baseturf_type, flags) - - SSair.remove_from_active(newT) - newT.CalculateAdjacentTurfs() - SSair.add_to_active(newT,1) + if(turf_type) + var/turf/newT = ChangeTurf(turf_type, baseturf_type, flags) + SSair.remove_from_active(newT) + newT.CalculateAdjacentTurfs() + SSair.add_to_active(newT,1) /turf/proc/copyTurf(turf/T) if(T.type != type) @@ -106,24 +106,26 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( return W // Take off the top layer turf and replace it with the next baseturf down -/turf/proc/ScrapeAway() +/turf/proc/ScrapeAway(amount=1, flags) + if(!amount) + return if(length(baseturfs)) - var/list/new_baseturfs = baseturfs - var/turf_type = new_baseturfs[new_baseturfs.len] - new_baseturfs.len-- - switch(new_baseturfs.len) - if(1) - new_baseturfs = new_baseturfs[1] - if(0) - new_baseturfs = turf_type - // We must never end up with a situation where there is no baseturf - WARNING("turf of type [type] had a baseturfs length 1 still in list form.") - return ChangeTurf(turf_type, new_baseturfs) + var/list/new_baseturfs = baseturfs.Copy() + var/turf_type = new_baseturfs[max(1, new_baseturfs.len - amount + 1)] + while(ispath(turf_type, /turf/baseturf_skipover)) + amount++ + if(amount > new_baseturfs.len) + CRASH("The bottomost baseturf of a turf is a skipover [src]([type])") + turf_type = new_baseturfs[max(1, new_baseturfs.len - amount + 1)] + new_baseturfs.len -= min(amount, new_baseturfs.len - 1) // No removing the very bottom + if(new_baseturfs.len == 1) + new_baseturfs = new_baseturfs[1] + return ChangeTurf(turf_type, new_baseturfs, flags) if(baseturfs == type) return src - return ChangeTurf(baseturfs, baseturfs) // The bottom baseturf will never go away + return ChangeTurf(baseturfs, baseturfs, flags) // The bottom baseturf will never go away // Take the input as baseturfs and put it underneath the current baseturfs // If fake_turf_type is provided and new_baseturfs is not the baseturfs list will be created identical to the turf type's @@ -153,6 +155,11 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( // Things placed on top of closed turfs will ignore the topmost closed turf // Returns the new turf /turf/proc/PlaceOnTop(list/new_baseturfs, turf/fake_turf_type, flags) + var/area/turf_area = loc + if(new_baseturfs && !length(new_baseturfs)) + new_baseturfs = list(new_baseturfs) + flags = turf_area.PlaceOnTopReact(new_baseturfs, fake_turf_type, flags) // A hook so areas can modify the incoming args + var/turf/newT if(flags & CHANGETURF_SKIP) // We haven't been initialized if(initialized) @@ -200,17 +207,16 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( new_baseturfs += type if(depth) - var/list/target_baseturfs = copytarget.baseturfs - target_baseturfs -= target_baseturfs & GLOB.blacklisted_automated_baseturfs - var/base_len = length(target_baseturfs) - if(!base_len) - if(!ignore_bottom) - new_baseturfs += target_baseturfs - else if(base_len > ignore_bottom) - if(base_len - ignore_bottom <= depth) - new_baseturfs += target_baseturfs.Copy(ignore_bottom + 1) - else - new_baseturfs += target_baseturfs.Copy(base_len - depth) + var/list/target_baseturfs + if(length(copytarget.baseturfs)) + // with default inputs this would be Copy(CLAMP(2, -INFINITY, baseturfs.len)) + // Don't forget a lower index is lower in the baseturfs stack, the bottom is baseturfs[1] + target_baseturfs = copytarget.baseturfs.Copy(CLAMP(1 + ignore_bottom, 1 + copytarget.baseturfs.len - depth, copytarget.baseturfs.len)) + else if(!ignore_bottom) + target_baseturfs = list(copytarget.baseturfs) + if(target_baseturfs) + target_baseturfs -= new_baseturfs & GLOB.blacklisted_automated_baseturfs + new_baseturfs += target_baseturfs var/turf/newT = copytarget.copyTurf(src) newT.baseturfs = new_baseturfs diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm index c73dd50e44..3515527bfd 100644 --- a/code/game/turfs/simulated/floor.dm +++ b/code/game/turfs/simulated/floor.dm @@ -4,6 +4,7 @@ //- floor_tile is now a path, and not a tile obj name = "floor" icon = 'icons/turf/floors.dmi' + baseturfs = /turf/open/floor/plating var/icon_regular_floor = "floor" //used to remember what icon the tile should have by default var/icon_plating = "plating" @@ -59,21 +60,25 @@ switch(severity) if(1) - ScrapeAway() + ScrapeAway(2) if(2) switch(pick(1,2;75,3)) if(1) - src.ReplaceWithLattice() + if(!length(baseturfs) || !ispath(baseturfs[baseturfs.len-1], /turf/open/floor)) + ScrapeAway() + ReplaceWithLattice() + else + ScrapeAway(2) if(prob(33)) new /obj/item/stack/sheet/metal(src) if(2) - ScrapeAway() + ScrapeAway(2) if(3) if(prob(80)) - src.break_tile_to_plating() + ScrapeAway() else - src.break_tile() - src.hotspot_expose(1000,CELL_VOLUME) + break_tile() + hotspot_expose(1000,CELL_VOLUME) if(prob(33)) new /obj/item/stack/sheet/metal(src) if(3) @@ -94,13 +99,15 @@ return 1 /turf/open/floor/attack_paw(mob/user) - return src.attack_hand(user) + return attack_hand(user) /turf/open/floor/proc/gets_drilled() return /turf/open/floor/proc/break_tile_to_plating() var/turf/open/floor/plating/T = make_plating() + if(!istype(T)) + return T.break_tile() /turf/open/floor/proc/break_tile() @@ -119,7 +126,7 @@ burnt = 1 /turf/open/floor/proc/make_plating() - return ChangeTurf(/turf/open/floor/plating) + return ScrapeAway() /turf/open/floor/ChangeTurf(path, new_baseturf, flags) if(!isfloorturf(src)) diff --git a/code/game/turfs/simulated/floor/mineral_floor.dm b/code/game/turfs/simulated/floor/mineral_floor.dm index 07e324bb02..e2e3356684 100644 --- a/code/game/turfs/simulated/floor/mineral_floor.dm +++ b/code/game/turfs/simulated/floor/mineral_floor.dm @@ -219,6 +219,7 @@ icon_state = "alienpod1" floor_tile = /obj/item/stack/tile/mineral/abductor icons = list("alienpod1", "alienpod2", "alienpod3", "alienpod4", "alienpod5", "alienpod6", "alienpod7", "alienpod8", "alienpod9") + baseturfs = /turf/open/floor/plating/abductor2 /turf/open/floor/mineral/abductor/Initialize() . = ..() @@ -229,6 +230,3 @@ /turf/open/floor/mineral/abductor/burn_tile() return //unburnable - -/turf/open/floor/mineral/abductor/make_plating() - return ChangeTurf(/turf/open/floor/plating/abductor2) diff --git a/code/game/turfs/simulated/floor/plating.dm b/code/game/turfs/simulated/floor/plating.dm index c2322fd594..eeed31bd9f 100644 --- a/code/game/turfs/simulated/floor/plating.dm +++ b/code/game/turfs/simulated/floor/plating.dm @@ -11,6 +11,7 @@ name = "plating" icon_state = "plating" intact = FALSE + baseturfs = /turf/open/space var/attachment_holes = TRUE /turf/open/floor/plating/examine(mob/user) @@ -55,7 +56,7 @@ to_chat(user, "You begin reinforcing the floor...") if(do_after(user, 30, target = src)) if (R.get_amount() >= 2 && !istype(src, /turf/open/floor/engine)) - ChangeTurf(/turf/open/floor/engine) + PlaceOnTop(/turf/open/floor/engine) playsound(src, 'sound/items/deconstruct.ogg', 80, 1) R.use(2) to_chat(user, "You reinforce the floor.") @@ -70,7 +71,7 @@ var/obj/item/stack/tile/W = C if(!W.use(1)) return - var/turf/open/floor/T = ChangeTurf(W.turf_type) + var/turf/open/floor/T = PlaceOnTop(W.turf_type) if(istype(W, /obj/item/stack/tile/light)) //TODO: get rid of this ugly check somehow var/obj/item/stack/tile/light/L = W var/turf/open/floor/light/F = T @@ -88,6 +89,9 @@ return TRUE +/turf/open/floor/plating/make_plating() + return + /turf/open/floor/plating/foam name = "metal foam plating" desc = "Thin, fragile flooring created with metal foam." diff --git a/code/game/turfs/simulated/floor/plating/asteroid.dm b/code/game/turfs/simulated/floor/plating/asteroid.dm index 1c174524bb..8cc61700d3 100644 --- a/code/game/turfs/simulated/floor/plating/asteroid.dm +++ b/code/game/turfs/simulated/floor/plating/asteroid.dm @@ -1,6 +1,4 @@ - - /**********************Asteroid**************************/ /turf/open/floor/plating/asteroid //floor piece @@ -43,12 +41,9 @@ if(..()) return TRUE if(istype(W, /obj/item/storage/bag/ore)) - var/obj/item/storage/bag/ore/S = W - if(S.collection_mode == 1) - for(var/obj/item/stack/ore/O in contents) - O.attackby(W,user) - return - + for(var/obj/item/stack/ore/O in src) + W.SendSignal(COMSIG_PARENT_ATTACKBY, O) + /turf/open/floor/plating/asteroid/singularity_act() if(is_planet_level(z)) return ..() @@ -198,6 +193,9 @@ if(istype(tunnel)) // Small chance to have forks in our tunnel; otherwise dig our tunnel. if(i > 3 && prob(20)) + if(istype(tunnel.loc, /area/mine/explored) || (istype(tunnel.loc, /area/lavaland/surface/outdoors) && !istype(tunnel.loc, /area/lavaland/surface/outdoors/unexplored))) + sanity = 0 + break var/turf/open/floor/plating/asteroid/airless/cave/C = tunnel.ChangeTurf(data_having_type, null, CHANGETURF_IGNORE_AIR) C.going_backwards = FALSE C.produce_tunnel_from_data(rand(10, 15), dir) @@ -216,7 +214,7 @@ /turf/open/floor/plating/asteroid/airless/cave/proc/SpawnFloor(turf/T) for(var/S in RANGE_TURFS(1, src)) var/turf/NT = S - if(!NT || isspaceturf(NT) || istype(NT.loc, /area/mine/explored) || istype(NT.loc, /area/lavaland/surface/outdoors/explored)) + if(!NT || isspaceturf(NT) || istype(NT.loc, /area/mine/explored) || (istype(NT.loc, /area/lavaland/surface/outdoors) && !istype(NT.loc, /area/lavaland/surface/outdoors/unexplored))) sanity = 0 break if(!sanity) diff --git a/code/game/turfs/simulated/floor/reinf_floor.dm b/code/game/turfs/simulated/floor/reinf_floor.dm index bdce6535ba..78fe2b1bde 100644 --- a/code/game/turfs/simulated/floor/reinf_floor.dm +++ b/code/game/turfs/simulated/floor/reinf_floor.dm @@ -37,7 +37,7 @@ if(!istype(src, /turf/open/floor/engine)) return TRUE new /obj/item/stack/rods(src, 2) - ChangeTurf(/turf/open/floor/plating) + ScrapeAway() return TRUE /turf/open/floor/engine/acid_act(acidpwr, acid_volume) @@ -55,14 +55,18 @@ switch(severity) if(1) if(prob(80)) - ReplaceWithLattice() + if(!length(baseturfs) || !ispath(baseturfs[baseturfs.len-1], /turf/open/floor)) + ScrapeAway() + ReplaceWithLattice() + else + ScrapeAway(2) else if(prob(50)) - ScrapeAway() + ScrapeAway(2) else - make_plating(1) + ScrapeAway() if(2) if(prob(50)) - make_plating(1) + ScrapeAway() /turf/open/floor/engine/singularity_pull(S, current_size) ..() diff --git a/code/game/turfs/simulated/lava.dm b/code/game/turfs/simulated/lava.dm index a70f44ac3f..f8ab060853 100644 --- a/code/game/turfs/simulated/lava.dm +++ b/code/game/turfs/simulated/lava.dm @@ -48,7 +48,7 @@ switch(passed_mode) if(RCD_FLOORWALL) to_chat(user, "You build a floor.") - ChangeTurf(/turf/open/floor/plating) + PlaceOnTop(/turf/open/floor/plating) return TRUE return FALSE diff --git a/code/game/turfs/simulated/minerals.dm b/code/game/turfs/simulated/minerals.dm index ee407926d8..09710e30a2 100644 --- a/code/game/turfs/simulated/minerals.dm +++ b/code/game/turfs/simulated/minerals.dm @@ -78,7 +78,7 @@ var/flags = NONE if(defer_change) // TODO: make the defer change var a var for any changeturf flag flags = CHANGETURF_DEFER_CHANGE - ChangeTurf(turf_type, null, flags) + ScrapeAway(null, flags) addtimer(CALLBACK(src, .proc/AfterChange), 1, TIMER_UNIQUE) playsound(src, 'sound/effects/break_stone.ogg', 50, 1) //beautiful destruction @@ -513,7 +513,7 @@ var/flags = NONE if(defer_change) flags = CHANGETURF_DEFER_CHANGE - ChangeTurf(turf_type, null, flags) + ScrapeAway(null, flags) addtimer(CALLBACK(src, .proc/AfterChange), 1, TIMER_UNIQUE) diff --git a/code/game/turfs/simulated/river.dm b/code/game/turfs/simulated/river.dm index 73640f99e0..e451fe4892 100644 --- a/code/game/turfs/simulated/river.dm +++ b/code/game/turfs/simulated/river.dm @@ -4,7 +4,7 @@ #define RANDOM_LOWER_X 50 #define RANDOM_LOWER_Y 50 -/proc/spawn_rivers(target_z, nodes = 4, turf_type = /turf/open/lava/smooth/lava_land_surface, whitelist_area = /area/lavaland/surface/outdoors, min_x = RANDOM_LOWER_X, min_y = RANDOM_LOWER_Y, max_x = RANDOM_UPPER_X, max_y = RANDOM_UPPER_Y) +/proc/spawn_rivers(target_z, nodes = 4, turf_type = /turf/open/lava/smooth/lava_land_surface, whitelist_area = /area/lavaland/surface/outdoors/unexplored, min_x = RANDOM_LOWER_X, min_y = RANDOM_LOWER_Y, max_x = RANDOM_UPPER_X, max_y = RANDOM_UPPER_Y) var/list/river_nodes = list() var/num_spawned = 0 var/list/possible_locs = block(locate(min_x, min_y, target_z), locate(max_x, max_y, target_z)) diff --git a/code/game/turfs/simulated/wall/mineral_walls.dm b/code/game/turfs/simulated/wall/mineral_walls.dm index 6cfa6a2f23..4f85d45d58 100644 --- a/code/game/turfs/simulated/wall/mineral_walls.dm +++ b/code/game/turfs/simulated/wall/mineral_walls.dm @@ -102,7 +102,7 @@ /turf/closed/wall/mineral/plasma/proc/PlasmaBurn(temperature) new girder_type(src) - src.ChangeTurf(/turf/open/floor/plasteel) + ScrapeAway() var/turf/open/T = src T.atmos_spawn_air("plasma=400;TEMP=[temperature]") diff --git a/code/game/turfs/simulated/wall/reinf_walls.dm b/code/game/turfs/simulated/wall/reinf_walls.dm index 6a68a894cf..c667714273 100644 --- a/code/game/turfs/simulated/wall/reinf_walls.dm +++ b/code/game/turfs/simulated/wall/reinf_walls.dm @@ -27,7 +27,7 @@ to_chat(user, "The support lines have been unscrewed, and the metal cover is welded firmly in place.") if(CUT_COVER) to_chat(user, "The metal cover has been sliced through, and is connected loosely to the girder.") - if(BOLTS) + if(ANCHOR_BOLTS) to_chat(user, "The outer cover has been pried away, and the bolts anchoring the support rods are wrenched in place.") if(SUPPORT_RODS) to_chat(user, "The bolts anchoring the support rods have been loosened, but are still welded firmly to the girder.") @@ -120,7 +120,7 @@ if(W.use_tool(src, user, 100, volume=100)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != CUT_COVER) return 1 - d_state = BOLTS + d_state = ANCHOR_BOLTS update_icon() to_chat(user, "You pry off the cover.") return 1 @@ -137,11 +137,11 @@ to_chat(user, "The metal cover has been welded securely to the frame.") return 1 - if(BOLTS) + if(ANCHOR_BOLTS) if(istype(W, /obj/item/wrench)) to_chat(user, "You start loosening the anchoring bolts which secure the support rods to their frame...") if(W.use_tool(src, user, 40, volume=100)) - if(!istype(src, /turf/closed/wall/r_wall) || d_state != BOLTS) + if(!istype(src, /turf/closed/wall/r_wall) || d_state != ANCHOR_BOLTS) return 1 d_state = SUPPORT_RODS update_icon() @@ -151,7 +151,7 @@ if(istype(W, /obj/item/crowbar)) to_chat(user, "You start to pry the cover back into place...") if(W.use_tool(src, user, 20, volume=100)) - if(!istype(src, /turf/closed/wall/r_wall) || d_state != BOLTS) + if(!istype(src, /turf/closed/wall/r_wall) || d_state != ANCHOR_BOLTS) return 1 d_state = CUT_COVER update_icon() @@ -177,7 +177,7 @@ if(W.use_tool(src, user, 40)) if(!istype(src, /turf/closed/wall/r_wall) || d_state != SUPPORT_RODS) return 1 - d_state = BOLTS + d_state = ANCHOR_BOLTS update_icon() to_chat(user, "You tighten the bolts anchoring the support rods.") return 1 diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 0cb72716fb..a40991b954 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -93,6 +93,9 @@ ..() /turf/attack_hand(mob/user) + . = ..() + if(.) + return user.Move_Pulled(src) /turf/proc/handleRCL(obj/item/twohanded/rcl/C, mob/user) @@ -265,15 +268,18 @@ /turf/proc/Bless() new /obj/effect/blessing(src) -/turf/storage_contents_dump_act(obj/item/storage/src_object, mob/user) - if(src_object.contents.len) +/turf/storage_contents_dump_act(datum/component/storage/src_object, mob/user) + . = ..() + if(.) + return + if(length(src_object.contents())) to_chat(usr, "You start dumping out the contents...") - if(!do_after(usr,20,target=src_object)) + if(!do_after(usr,20,target=src_object.parent)) return FALSE - var/list/things = src_object.contents.Copy() + var/list/things = src_object.contents() var/datum/progressbar/progress = new(user, things.len, src) - while (do_after(usr, 10, TRUE, src, FALSE, CALLBACK(src_object, /obj/item/storage.proc/mass_remove_from_storage, src, things, progress))) + while (do_after(usr, 10, TRUE, src, FALSE, CALLBACK(src_object, /datum/component/storage.proc/mass_remove_from_storage, src, things, progress))) stoplag(1) qdel(progress)