/* Stack type objects! * Contains: * Stacks * Recipe datum */ /* * Stacks */ /obj/item/stack gender = PLURAL origin_tech = Tc_MATERIALS + "=1" icon = 'icons/obj/stacks_sheets.dmi' var/list/datum/stack_recipe/recipes var/singular_name var/irregular_plural //"Teeth", for example. Without this, you'd see "There are 30 tooths in the stack." var/amount = 1 var/perunit = 3750 var/max_amount //also see stack recipes initialisation, param "max_res_amount" must be equal to this max_amount var/redeemed = 0 // For selling minerals to central command via supply shuttle. var/restock_amount = 0 //For borg chargers restocking. var/sheettype = null //this is used for girders in the creation of walls/false walls. Used by both tiles and sheets. var/last_work = 0 //rounded last world.time at which a crafting began /obj/item/stack/New(var/loc, var/amount=null) ..() if (amount) src.amount=amount update_materials() update_icon() //forceMove(loc) // So that Crossed gets called, so that stacks can be merged initial_thermal_mass = thermal_mass thermal_mass = initial_thermal_mass * src.amount /obj/item/stack/Destroy() if (usr && usr.machine==src) usr << browse(null, "window=stack") ..() /obj/item/stack/examine(mob/user) ..() var/be = "are" if(amount == 1) be = "is" to_chat(user, "There [be] [src.amount] [correct_name()] in the stack.") /obj/item/stack/proc/correct_name() return "[irregular_plural && amount > 1 ? irregular_plural : "[singular_name]"][amount == 1 || irregular_plural ? "" : "s"]" /obj/item/stack/attack_self(mob/user as mob) list_recipes(user) /obj/item/stack/proc/list_recipes(mob/user as mob, recipes_sublist) ASSERT(isnum(amount)) if(!recipes) return if(!src || amount <= 0) user << browse(null, "window=stack") user.set_machine(src) //for correct work of onclose var/list/recipe_list = recipes if(recipes_sublist && recipe_list[recipes_sublist] && istype(recipe_list[recipes_sublist], /datum/stack_recipe_list)) var/datum/stack_recipe_list/srl = recipe_list[recipes_sublist] recipe_list = srl.recipes var/t1 = "[name] recipesAmount of [name] available: [src.amount]
" for(var/i = 1;i <= recipe_list.len,i++) var/E = recipe_list[i] if(isnull(E)) t1 += "
" continue if(i > 1 && !isnull(recipe_list[i-1])) t1 += "
" if(istext(E)) t1 += "[E]" if(istype(E, /datum/stack_recipe_list)) var/datum/stack_recipe_list/srl = E var/stack_name = (irregular_plural && srl.req_amount > 1) ? irregular_plural : "[singular_name]\s" if(src.amount >= srl.req_amount) t1 += "[srl.title] ([srl.req_amount] [stack_name])" else t1 += "[srl.title] ([srl.req_amount] [stack_name]\s)
" if(istype(E, /datum/stack_recipe)) var/datum/stack_recipe/R = E var/turf/T = get_turf(src) if(!T || (R.z_up_required && !HasAbove(T.z)) || (R.z_down_required && !HasBelow(T.z))) continue var/max_multiplier = round(src.amount / R.req_amount) var/title var/can_build = 1 can_build = can_build && (max_multiplier>0) if(R.res_amount > 1) title += "[R.res_amount]x [R.title]\s" else title += "[R.title]" title += " ([R.req_amount] [correct_name()])" if(R.other_reqs.len) for(var/ii = 1 to R.other_reqs.len) can_build = 0 var/obj/looking_for = R.other_reqs[ii] var/req_amount if(ispath(looking_for, /obj/item/stack)) var/obj/item/stack/S = new looking_for req_amount = R.other_reqs[looking_for] title += ", [req_amount] [S.correct_name()]" else title += ", [initial(looking_for.name)] required in vicinity" if(ispath(user.get_inactive_hand(), looking_for)) if(req_amount) var/obj/item/stack/S = user.get_inactive_hand() if(S.amount >= req_amount) can_build = 1 continue if(!can_build) for(var/obj/I in range(get_turf(src),1)) if(ispath(looking_for, I)) if(req_amount) //It's of a stack/sheet subtype var/obj/item/stack/S = I if(S.amount >= req_amount) can_build = 1 continue else can_build = 1 continue break if(can_build) t1 += "[title]" else t1 += "[title]" continue if(R.max_res_amount > 1 && max_multiplier > 1) max_multiplier = min(max_multiplier, round(R.max_res_amount/R.res_amount)) t1 += " |" var/list/multipliers = list(5, 10, 25) for(var/n in multipliers) if(max_multiplier>=n) t1 += " [n*R.res_amount]x" if (!(max_multiplier in multipliers)) t1 += " [max_multiplier*R.res_amount]x" t1 += extra_message() t1 += "
" user << browse(t1, "window=stack") onclose(user, "stack") return /obj/item/stack/proc/extra_message() return null /obj/item/stack/proc/time_modifier(var/_time) return _time /obj/item/stack/proc/loc_override() return null /obj/item/stack/proc/allow_use(var/mob/living/user) return (user.get_active_hand() == src) /obj/item/stack/proc/stop_build(var/_last_crafting = FALSE) return /obj/item/stack/useThermalMass(var/used_mass) ..() var/used_amount = round(initial_thermal_mass * amount - thermal_mass) use(used_amount) /obj/item/stack/Topic(href, href_list) ..() if ((usr.restrained() || usr.stat || !allow_use(usr))) return if (href_list["sublist"] && !href_list["make"]) list_recipes(usr, text2num(href_list["sublist"])) if (href_list["make"]) if (src.amount < 1) qdel(src) //Never should happen var/list/recipes_list = recipes if (href_list["sublist"]) var/datum/stack_recipe_list/srl = recipes_list[text2num(href_list["sublist"])] recipes_list = srl.recipes var/datum/stack_recipe/R = recipes_list[text2num(href_list["make"])] var/multiplier = text2num(href_list["multiplier"]) R.build(usr, src, multiplier, loc_override()) if (src && usr.machine==src) //do not reopen closed window spawn( 0 ) src.interact(usr) return return /obj/item/stack/proc/use(var/amount) ASSERT(isnum(src.amount)) if (src.amount <= 0) qdel(src) // We don't have anything left return if(src.amount>=amount) var/thermal_mass_used = thermal_mass/src.amount src.amount-=amount thermal_mass -= thermal_mass_used update_materials() else return 0 . = 1 if (src.amount<=0) //If the stack is empty after removing the required amount of items! on_empty() spawn() qdel(src) /obj/item/stack/proc/on_empty() if(usr) if(istype(usr,/mob/living/silicon/robot)) var/mob/living/silicon/robot/R=usr if(R.module) R.module.modules -= src if(R.module_active == src) R.module_active = null if(R.module_state_1 == src) R.uneq_module(R.module_state_1) R.module_state_1 = null R.inv1.icon_state = "inv1" else if(R.module_state_2 == src) R.uneq_module(R.module_state_2) R.module_state_2 = null R.inv2.icon_state = "inv2" else if(R.module_state_3 == src) R.uneq_module(R.module_state_3) R.module_state_3 = null R.inv3.icon_state = "inv3" usr.before_take_item(src) /obj/item/stack/proc/add(var/amount) src.amount += amount if(thermal_mass) thermal_mass += initial_thermal_mass * amount update_materials() /obj/item/stack/proc/set_amount(new_amount) amount = new_amount update_materials() /obj/item/stack/proc/merge(obj/item/stack/S) //Merge src into S, as much as possible if(src == S) //We need to check this because items can cross themselves for some fucked up reason return if(!can_stack_with(S)) return var/transfer = min(amount, S.max_amount - S.amount) if(transfer <= 0) return if(pulledby) pulledby.start_pulling(S) S.copy_evidences(src) S.transfer_data_from(src,transfer) update_icon() S.update_icon() use(transfer) S.add(transfer) /obj/item/stack/proc/update_materials() if(amount && starting_materials) for(var/matID in starting_materials) materials.storage[matID] = max(0, starting_materials[matID]*amount) if(amount < 2) gender = NEUTER else gender = PLURAL /obj/item/stack/proc/can_stack_with(obj/item/other_stack) if(ispath(other_stack)) return (src.type == other_stack) return (src.type == other_stack.type) /obj/item/stack/attack_hand(mob/user as mob) if (user.get_inactive_hand() == src) var/obj/item/stack/F = new src.type( user, amount=1) F.copy_evidences(src) F.material_type = material_type user.put_in_hands(F) src.add_fingerprint(user) F.add_fingerprint(user) F.transfer_data_from(src,1) use(1) update_icon() F.update_icon() if (src && usr.machine==src) spawn(0) src.interact(usr) else ..() return /obj/item/stack/proc/transfer_data_from(var/obj/item/stack/S, var/amount) return /obj/item/stack/preattack(atom/target, mob/user, proximity_flag, click_parameters) if (!proximity_flag) return 0 if (can_stack_with(target)) var/obj/item/stack/S = target if (amount >= max_amount) to_chat(user, "\The [src] cannot hold anymore [correct_name()].") return 1 var/to_transfer if (user.get_inactive_hand()==S) to_transfer = 1 else to_transfer = min(S.amount, max_amount-amount) add(to_transfer) transfer_data_from(S,to_transfer) to_chat(user, "You add [to_transfer] [((to_transfer > 1) && S.irregular_plural) ? S.irregular_plural : "[S.singular_name]\s"] to \the [src]. It now contains [amount] [correct_name()].") if (S && user.machine==S) spawn(0) interact(user) S.use(to_transfer) if (src && user.machine==src) spawn(0) src.interact(user) update_icon() S.update_icon() return 1 return ..() //Ported from -tg-station/#10973, credit to MrPerson /obj/item/stack/Crossed(obj/o) if(src != o && istype(o, src.type) && !o.throwing) merge(o) return ..() /obj/item/stack/hitby(atom/movable/AM) //Doesn't seem to ever be called since stacks are not dense but whatever . = ..() if(.) return if(src != AM && istype(AM, src.type)) merge(AM) /obj/item/stack/proc/copy_evidences(obj/item/stack/from as obj) src.blood_DNA = from.blood_DNA src.fingerprints = from.fingerprints src.fingerprintshidden = from.fingerprintshidden src.fingerprintslast = from.fingerprintslast //TODO bloody overlay /* drop_stack() helper proc Arguments: - new_stack_type = type of stack to spawn (for example /obj/item/stack/tile/light) - loc = where to spawn the stack - add_amount = how much items to create in the stack - user = non-essential, whom to send the messages to This proc sees if there are any stacks of the same type in *loc. If there are, and it's possible to add *amount items to them, add *amount items to them and return. If unable to add to any already existing stack, create a new instance of *new_stack_type Returns stack */ /proc/drop_stack(new_stack_type = /obj/item/stack, atom/loc, add_amount = 1, mob/user) if(!ispath(new_stack_type, /obj/item/stack)) return new new_stack_type(loc) for(var/obj/item/stack/S in loc) if(S.can_stack_with(new_stack_type)) if(S.max_amount >= S.amount + add_amount) S.add(add_amount) if(user) to_chat(user, "You add [add_amount] item\s to the stack. It now contains [S.amount] [S.correct_name()].") return S var/obj/item/stack/S = new_stack_type for(var/i = 0 to round(add_amount/initial(S.max_amount))) if (add_amount <= 0) continue S = new new_stack_type(loc) S.amount = min(add_amount, S.max_amount) add_amount -= S.amount S.update_materials() S.update_icon() return S /obj/item/stack/verb_pickup(mob/living/user) var/obj/item/I = user.get_active_hand() if(I && can_stack_with(I)) I.preattack(src, user, 1) return return ..() /obj/item/stack/restock() if(!restock_amount) return //Do not restock this stack type if(amount < max_amount) amount += restock_amount if(amount > max_amount) amount = max_amount