GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/effects/fire.dmi', "fire")) GLOBAL_VAR_INIT(rpg_loot_items, FALSE) // if true, everyone item when created will have its name changed to be // more... RPG-like. GLOBAL_VAR_INIT(stickpocalypse, FALSE) // if true, all non-embeddable items will be able to harmlessly stick to people when thrown GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to embed in people, takes precedence over stickpocalypse /obj/item name = "item" icon = 'icons/obj/items_and_weapons.dmi' blocks_emissive = EMISSIVE_BLOCK_GENERIC ///icon state name for inhand overlays var/item_state = null ///Icon file for left hand inhand overlays var/lefthand_file = 'icons/mob/inhands/items_lefthand.dmi' ///Icon file for right inhand overlays var/righthand_file = 'icons/mob/inhands/items_righthand.dmi' ///Icon file for mob worn overlays. ///no var for state because it should *always* be the same as icon_state var/icon/mob_overlay_icon ///Forced mob worn layer instead of the standard preferred ssize. var/alternate_worn_layer ///Dimensions of the icon file used when this item is worn, eg: hats.dmi (32x32 sprite, 64x64 sprite, etc.). Allows inhands/worn sprites to be of any size, but still centered on a mob properly var/worn_x_dimension = 32 ///Dimensions of the icon file used when this item is worn, eg: hats.dmi (32x32 sprite, 64x64 sprite, etc.). Allows inhands/worn sprites to be of any size, but still centered on a mob properly var/worn_y_dimension = 32 ///Same as for [worn_x_dimension][/obj/item/var/worn_x_dimension] but for inhands, uses the lefthand_ and righthand_ file vars var/inhand_x_dimension = 32 ///Same as for [worn_y_dimension][/obj/item/var/worn_y_dimension] but for inhands, uses the lefthand_ and righthand_ file vars var/inhand_y_dimension = 32 max_integrity = 200 obj_flags = NONE ///Item flags for the item var/item_flags = NONE ///Sound played when you hit something with the item var/hitsound ///Played when the item is used, for example tools var/usesound ///Used when yate into a mob var/mob_throw_hit_sound ///Sound used when equipping the item into a valid slot var/equip_sound ///Sound uses when picking the item up (into your hands) var/pickup_sound ///Sound uses when dropping the item, or when its thrown. var/drop_sound ///How large is the object, used for stuff like whether it can fit in backpacks or not var/w_class = WEIGHT_CLASS_NORMAL ///This is used to determine on which slots an item can fit. var/slot_flags = 0 pass_flags = PASSTABLE pressure_resistance = 4 var/obj/item/master = null ///flags which determine which body parts are protected from heat. [See here][HEAD] var/heat_protection = 0 ///flags which determine which body parts are protected from cold. [See here][HEAD] var/cold_protection = 0 ///Set this variable to determine up to which temperature (IN KELVIN) the item protects against heat damage. Keep at null to disable protection. Only protects areas set by heat_protection flags var/max_heat_protection_temperature ///Set this variable to determine down to which temperature (IN KELVIN) the item protects against cold damage. 0 is NOT an acceptable number due to if(varname) tests!! Keep at null to disable protection. Only protects areas set by cold_protection flags var/min_cold_protection_temperature ///list of /datum/action's that this item has. var/list/actions ///list of paths of action datums to give to the item on New(). var/list/actions_types //Since any item can now be a piece of clothing, this has to be put here so all items share it. ///This flag is used to determine when items in someone's inventory cover others. IE helmets making it so you can't see glasses, etc. var/flags_inv ///you can see someone's mask through their transparent visor, but you can't reach it var/transparent_protection = NONE ///flags for what should be done when you click on the item, default is picking it up var/interaction_flags_item = INTERACT_ITEM_ATTACK_HAND_PICKUP ///What body parts are covered by the clothing when you wear it var/body_parts_covered = 0 ///Literally does nothing right now var/gas_transfer_coefficient = 1 /// How likely a disease or chemical is to get through a piece of clothing var/permeability_coefficient = 1 /// for electrical admittance/conductance (electrocution checks and shit) var/siemens_coefficient = 1 /// How much clothing is slowing you down. Negative values speeds you up var/slowdown = 0 ///percentage of armour effectiveness to remove var/armour_penetration = 0 ///What objects the suit storage can store var/list/allowed = null ///In deciseconds, how long an item takes to equip; counts only for normal clothing slots, not pockets etc. var/equip_delay_self = 0 ///In deciseconds, how long an item takes to put on another person var/equip_delay_other = 20 ///In deciseconds, how long an item takes to remove from another person var/strip_delay = 40 ///How long it takes to resist out of the item (cuffs and such) var/breakouttime = 0 ///Used in [atom/proc/attackby] to say how something was attacked "[x] has been [z.attack_verb] by [y] with [z]" var/list/attack_verb ///list() of species types, if a species cannot put items in a certain slot, but species type is in list, it will be able to wear that item var/list/species_exception = null ///Who threw the item var/mob/thrownby = null ///the icon to indicate this object is being dragged mouse_drag_pointer = MOUSE_ACTIVE_POINTER ///Does it embed and if yes, what kind of embed var/list/embedding = NONE ///for flags such as [GLASSESCOVERSEYES] var/flags_cover = 0 var/heat = 0 ///All items with sharpness of IS_SHARP or higher will automatically get the butchering component. var/sharpness = IS_BLUNT ///How a tool acts when you use it on something, such as wirecutters cutting wires while multitools measure power var/tool_behaviour = NONE ///How fast does the tool work var/toolspeed = 1 var/block_chance = 0 var/hit_reaction_chance = 0 //If you want to have something unrelated to blocking/armour piercing etc. Maybe not needed, but trying to think ahead/allow more freedom ///In tiles, how far this weapon can reach; 1 for adjacent, which is default var/reach = 1 ///The list of slots by priority. equip_to_appropriate_slot() uses this list. Doesn't matter if a mob type doesn't have a slot. For default list, see [/mob/proc/equip_to_appropriate_slot] var/list/slot_equipment_priority = null ///Reference to the datum that determines whether dogs can wear the item: Needs to be in /obj/item because corgis can wear a lot of non-clothing items var/datum/dog_fashion/dog_fashion = null //Tooltip vars ///string form of an item's force. Edit this var only to set a custom force string var/force_string var/last_force_string_check = 0 var/tip_timer ///Determines who can shoot this var/trigger_guard = TRIGGER_GUARD_NONE ///Used as the dye color source in the washing machine only (at the moment). Can be a hex color or a key corresponding to a registry entry, see washing_machine.dm var/dye_color ///Whether the item is unaffected by standard dying. var/undyeable = FALSE ///What dye registry should be looked at when dying this item; see washing_machine.dm var/dying_key ///Grinder var:A reagent list containing the reagents this item produces when ground up in a grinder - this can be an empty list to allow for reagent transferring only var/list/grind_results //Grinder var:A reagent list containing blah blah... but when JUICED in a grinder! var/list/juice_results var/canMouseDown = FALSE /obj/item/Initialize() if(attack_verb) attack_verb = typelist("attack_verb", attack_verb) . = ..() for(var/path in actions_types) new path(src) actions_types = null if(force_string) item_flags |= FORCE_STRING_OVERRIDE if(!hitsound) if(damtype == "fire") hitsound = 'sound/items/welder.ogg' if(damtype == "brute") hitsound = "swing_hit" /obj/item/Destroy() item_flags &= ~DROPDEL //prevent reqdels if(ismob(loc)) var/mob/m = loc m.temporarilyRemoveItemFromInventory(src, TRUE) for(var/X in actions) qdel(X) return ..() /obj/item/proc/check_allowed_items(atom/target, not_inside, target_self) if(((src in target) && !target_self) || (!isturf(target.loc) && !isturf(target) && not_inside)) return 0 else return 1 /obj/item/blob_act(obj/structure/blob/B) if(B && B.loc == loc) qdel(src) /obj/item/ComponentInitialize() . = ..() // this proc says it's for initializing components, but we're initializing elements too because it's you and me against the world >:) if(!LAZYLEN(embedding)) if(GLOB.embedpocalypse) embedding = EMBED_POINTY name = "pointy [name]" else if(GLOB.stickpocalypse) embedding = EMBED_HARMLESS name = "sticky [name]" updateEmbedding() if(GLOB.rpg_loot_items) AddComponent(/datum/component/fantasy) if(sharpness) //give sharp objects butchering functionality, for consistency AddComponent(/datum/component/butchering, 80 * toolspeed) /**Makes cool stuff happen when you suicide with an item * *Outputs a creative message and then return the damagetype done * Arguments: * * user: The mob that is suiciding */ /obj/item/proc/suicide_act(mob/user) return /obj/item/verb/move_to_top() set name = "Move To Top" set category = "Object" set src in oview(1) if(!isturf(loc) || usr.stat || usr.restrained()) return if(isliving(usr)) var/mob/living/L = usr if(!(L.mobility_flags & MOBILITY_PICKUP)) return var/turf/T = loc loc = null loc = T /obj/item/examine(mob/user) //This might be spammy. Remove? . = ..() . += "[gender == PLURAL ? "They are" : "It is"] a [weightclass2text(w_class)] item." if(resistance_flags & INDESTRUCTIBLE) . += "[src] seems extremely robust! It'll probably withstand anything that could happen to it!" else if(resistance_flags & LAVA_PROOF) . += "[src] is made of an extremely heat-resistant material, it'd probably be able to withstand lava!" if(resistance_flags & (ACID_PROOF | UNACIDABLE)) . += "[src] looks pretty robust! It'd probably be able to withstand acid!" if(resistance_flags & FREEZE_PROOF) . += "[src] is made of cold-resistant materials." if(resistance_flags & FIRE_PROOF) . += "[src] is made of fire-retardant materials." if(!user.research_scanner) return /// Research prospects, including boostable nodes and point values. Deliver to a console to know whether the boosts have already been used. var/list/research_msg = list("Research prospects: ") ///Separator between the items on the list var/sep = "" ///Nodes that can be boosted var/list/boostable_nodes = techweb_item_boost_check(src) if (boostable_nodes) for(var/id in boostable_nodes) var/datum/techweb_node/node = SSresearch.techweb_node_by_id(id) if(!node) continue research_msg += sep research_msg += node.display_name sep = ", " var/list/points = techweb_item_point_check(src) if (length(points)) sep = ", " research_msg += techweb_point_display_generic(points) if (!sep) // nothing was shown research_msg += "None" // Extractable materials. Only shows the names, not the amounts. research_msg += ".
Extractable materials: " if (length(custom_materials)) sep = "" for(var/mat in custom_materials) research_msg += sep research_msg += CallMaterialName(mat) sep = ", " else research_msg += "None" research_msg += "." . += research_msg.Join() /obj/item/interact(mob/user) add_fingerprint(user) ui_interact(user) /obj/item/ui_act(action, list/params) add_fingerprint(usr) return ..() /obj/item/attack_hand(mob/user) . = ..() if(.) return if(!user) return if(anchored) return if(resistance_flags & ON_FIRE) var/mob/living/carbon/C = user var/can_handle_hot = FALSE if(!istype(C)) can_handle_hot = TRUE else if(C.gloves && (C.gloves.max_heat_protection_temperature > 360)) can_handle_hot = TRUE else if(HAS_TRAIT(C, TRAIT_RESISTHEAT) || HAS_TRAIT(C, TRAIT_RESISTHEATHANDS)) can_handle_hot = TRUE if(can_handle_hot) extinguish() to_chat(user, "You put out the fire on [src].") else to_chat(user, "You burn your hand on [src]!") var/obj/item/bodypart/affecting = C.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage C.update_damage_overlays() return if(acid_level > 20 && !ismob(loc))// so we can still remove the clothes on us that have acid. var/mob/living/carbon/C = user if(istype(C)) if(!C.gloves || (!(C.gloves.resistance_flags & (UNACIDABLE|ACID_PROOF)))) to_chat(user, "The acid on [src] burns your hand!") var/obj/item/bodypart/affecting = C.get_bodypart("[(user.active_hand_index % 2 == 0) ? "r" : "l" ]_arm") if(affecting && affecting.receive_damage( 0, 5 )) // 5 burn damage C.update_damage_overlays() if(!(interaction_flags_item & INTERACT_ITEM_ATTACK_HAND_PICKUP)) //See if we're supposed to auto pickup. return //Heavy gravity makes picking up things very slow. var/grav = user.has_gravity() if(grav > STANDARD_GRAVITY) var/grav_power = min(3,grav - STANDARD_GRAVITY) to_chat(user,"You start picking up [src]...") if(!do_mob(user,src,30*grav_power)) return //If the item is in a storage item, take it out SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE) if(QDELETED(src)) //moving it out of the storage to the floor destroyed it. return if(throwing) throwing.finalize(FALSE) if(loc == user) if(!allow_attack_hand_drop(user) || !user.temporarilyRemoveItemFromInventory(src)) return pickup(user) add_fingerprint(user) if(!user.put_in_active_hand(src, FALSE, FALSE)) user.dropItemToGround(src) /obj/item/proc/allow_attack_hand_drop(mob/user) return TRUE /obj/item/attack_paw(mob/user) if(!user) return if(anchored) return SEND_SIGNAL(loc, COMSIG_TRY_STORAGE_TAKE, src, user.loc, TRUE) if(throwing) throwing.finalize(FALSE) if(loc == user) if(!user.temporarilyRemoveItemFromInventory(src)) return pickup(user) add_fingerprint(user) if(!user.put_in_active_hand(src, FALSE, FALSE)) user.dropItemToGround(src) /obj/item/attack_alien(mob/user) var/mob/living/carbon/alien/A = user if(!A.has_fine_manipulation) if(src in A.contents) // To stop Aliens having items stuck in their pockets A.dropItemToGround(src) to_chat(user, "Your claws aren't capable of such fine manipulation!") return attack_paw(A) /obj/item/attack_ai(mob/user) if(istype(src.loc, /obj/item/robot_module)) //If the item is part of a cyborg module, equip it if(!iscyborg(user)) return var/mob/living/silicon/robot/R = user if(!R.low_power_mode) //can't equip modules with an empty cell. R.activate_module(src) R.hud_used.update_robot_modules_display() /obj/item/proc/GetDeconstructableContents() return GetAllContents() - src // afterattack() and attack() prototypes moved to _onclick/item_attack.dm for consistency /obj/item/proc/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK) SEND_SIGNAL(src, COMSIG_ITEM_HIT_REACT, args) if(prob(final_block_chance)) owner.visible_message("[owner] blocks [attack_text] with [src]!") return 1 return 0 /obj/item/proc/talk_into(mob/M, input, channel, spans, datum/language/language) return ITALICS | REDUCE_RANGE /obj/item/proc/dropped(mob/user, silent = FALSE) SHOULD_CALL_PARENT(1) for(var/X in actions) var/datum/action/A = X A.Remove(user) if(item_flags & DROPDEL) qdel(src) item_flags &= ~IN_INVENTORY SEND_SIGNAL(src, COMSIG_ITEM_DROPPED,user) if(!silent) playsound(src, drop_sound, DROP_SOUND_VOLUME, ignore_walls = FALSE) user?.update_equipment_speed_mods() /// called just as an item is picked up (loc is not yet changed) /obj/item/proc/pickup(mob/user) SHOULD_CALL_PARENT(1) SEND_SIGNAL(src, COMSIG_ITEM_PICKUP, user) item_flags |= IN_INVENTORY /// called when "found" in pockets and storage items. Returns 1 if the search should end. /obj/item/proc/on_found(mob/finder) return /** *called after an item is placed in an equipment slot * Arguments: * * user is mob that equipped it * * slot uses the slot_X defines found in setup.dm for items that can be placed in multiple slots * * Initial is used to indicate whether or not this is the initial equipment (job datums etc) or just a player doing it */ /obj/item/proc/equipped(mob/user, slot, initial = FALSE) SHOULD_CALL_PARENT(1) SEND_SIGNAL(src, COMSIG_ITEM_EQUIPPED, user, slot) for(var/X in actions) var/datum/action/A = X if(item_action_slot_check(slot, user)) //some items only give their actions buttons when in a specific slot. A.Grant(user) item_flags |= IN_INVENTORY if(!initial) if(equip_sound && (slot_flags & slot)) playsound(src, equip_sound, EQUIP_SOUND_VOLUME, TRUE, ignore_walls = FALSE) else if(slot == ITEM_SLOT_HANDS) playsound(src, pickup_sound, PICKUP_SOUND_VOLUME, ignore_walls = FALSE) user.update_equipment_speed_mods() ///sometimes we only want to grant the item's action if it's equipped in a specific slot. /obj/item/proc/item_action_slot_check(slot, mob/user) if(slot == ITEM_SLOT_BACKPACK || slot == ITEM_SLOT_LEGCUFFED) //these aren't true slots, so avoid granting actions there return FALSE return TRUE /** *the mob M is attempting to equip this item into the slot passed through as 'slot'. Return 1 if it can do this and 0 if it can't. *if this is being done by a mob other than M, it will include the mob equipper, who is trying to equip the item to mob M. equipper will be null otherwise. *If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen. * Arguments: * * disable_warning to TRUE if you wish it to not give you text outputs. * * slot is the slot we are trying to equip to * * equipper is the mob trying to equip the item * * bypass_equip_delay_self for whether we want to bypass the equip delay */ /obj/item/proc/mob_can_equip(mob/living/M, mob/living/equipper, slot, disable_warning = FALSE, bypass_equip_delay_self = FALSE, swap = FALSE) if(!M) return FALSE return M.can_equip(src, slot, disable_warning, bypass_equip_delay_self, swap) /obj/item/verb/verb_pickup() set src in oview(1) set category = "Object" set name = "Pick up" if(usr.incapacitated() || !Adjacent(usr)) return if(isliving(usr)) var/mob/living/L = usr if(!(L.mobility_flags & MOBILITY_PICKUP)) return if(usr.get_active_held_item() == null) // Let me know if this has any problems -Yota usr.UnarmedAttack(src) /** *This proc is executed when someone clicks the on-screen UI button. *The default action is attack_self(). *Checks before we get to here are: mob is alive, mob is not restrained, stunned, asleep, resting, laying, item is on the mob. */ /obj/item/proc/ui_action_click(mob/user, actiontype) attack_self(user) ///This proc determines if and at what an object will reflect energy projectiles if it's in l_hand,r_hand or wear_suit /obj/item/proc/IsReflect(var/def_zone) return FALSE /obj/item/proc/eyestab(mob/living/carbon/M, mob/living/carbon/user) var/is_human_victim var/obj/item/bodypart/affecting = M.get_bodypart(BODY_ZONE_HEAD) if(ishuman(M)) if(!affecting) //no head! return is_human_victim = TRUE if(M.is_eyes_covered()) // you can't stab someone in the eyes wearing a mask! to_chat(user, "You're going to need to remove [M.p_their()] eye protection first!") return if(isalien(M))//Aliens don't have eyes./N slimes also don't have eyes! to_chat(user, "You cannot locate any eyes on this creature!") return if(isbrain(M)) to_chat(user, "You cannot locate any organic eyes on this brain!") return src.add_fingerprint(user) playsound(loc, src.hitsound, 30, TRUE, -1) user.do_attack_animation(M) if(M != user) M.visible_message("[user] stabs [M] in the eye with [src]!", \ "[user] stabs you in the eye with [src]!") else user.visible_message( \ "[user] stabs [user.p_them()]self in the eyes with [src]!", \ "You stab yourself in the eyes with [src]!" \ ) if(is_human_victim) var/mob/living/carbon/human/U = M U.apply_damage(7, BRUTE, affecting) else M.take_bodypart_damage(7) SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "eye_stab", /datum/mood_event/eye_stab) log_combat(user, M, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])") var/obj/item/organ/eyes/eyes = M.getorganslot(ORGAN_SLOT_EYES) if (!eyes) return M.adjust_blurriness(3) eyes.applyOrganDamage(rand(2,4)) if(eyes.damage >= 10) M.adjust_blurriness(15) if(M.stat != DEAD) to_chat(M, "Your eyes start to bleed profusely!") if(!(M.is_blind() || HAS_TRAIT(M, TRAIT_NEARSIGHT))) to_chat(M, "You become nearsighted!") M.become_nearsighted(EYE_DAMAGE) if(prob(50)) if(M.stat != DEAD) if(M.drop_all_held_items()) to_chat(M, "You drop what you're holding and clutch at your eyes!") M.adjust_blurriness(10) M.Unconscious(20) M.Paralyze(40) if (prob(eyes.damage - 10 + 1)) M.become_blind(EYE_DAMAGE) to_chat(M, "You go blind!") /obj/item/singularity_pull(S, current_size) ..() if(current_size >= STAGE_FOUR) throw_at(S,14,3, spin=0) else return /obj/item/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum) if(hit_atom && !QDELETED(hit_atom)) SEND_SIGNAL(src, COMSIG_MOVABLE_IMPACT, hit_atom, throwingdatum) if(get_temperature() && isliving(hit_atom)) var/mob/living/L = hit_atom L.IgniteMob() var/itempush = 1 if(w_class < 4) itempush = 0 //too light to push anything if(istype(hit_atom, /mob/living)) //Living mobs handle hit sounds differently. var/volume = get_volume_by_throwforce_and_or_w_class() if (throwforce > 0) if (mob_throw_hit_sound) playsound(hit_atom, mob_throw_hit_sound, volume, TRUE, -1) else if(hitsound) playsound(hit_atom, hitsound, volume, TRUE, -1) else playsound(hit_atom, 'sound/weapons/genhit.ogg',volume, TRUE, -1) else playsound(hit_atom, 'sound/weapons/throwtap.ogg', 1, volume, -1) else playsound(src, drop_sound, YEET_SOUND_VOLUME, ignore_walls = FALSE) return hit_atom.hitby(src, 0, itempush, throwingdatum=throwingdatum) /obj/item/throw_at(atom/target, range, speed, mob/thrower, spin=1, diagonals_first = 0, datum/callback/callback, force, gentle = FALSE, quickstart = TRUE) if(HAS_TRAIT(src, TRAIT_NODROP)) return thrownby = thrower callback = CALLBACK(src, .proc/after_throw, callback) //replace their callback with our own . = ..(target, range, speed, thrower, spin, diagonals_first, callback, force, gentle, quickstart = quickstart) /obj/item/proc/after_throw(datum/callback/callback) if (callback) //call the original callback . = callback.Invoke() item_flags &= ~IN_INVENTORY if(!pixel_y && !pixel_x) pixel_x = rand(-8,8) pixel_y = rand(-8,8) /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 FALSE if(SEND_SIGNAL(loc, COMSIG_CONTAINS_STORAGE)) return SEND_SIGNAL(loc, 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) /obj/item/proc/update_slot_icon() if(!ismob(loc)) return var/mob/owner = loc var/flags = slot_flags if(flags & ITEM_SLOT_OCLOTHING) owner.update_inv_wear_suit() if(flags & ITEM_SLOT_ICLOTHING) owner.update_inv_w_uniform() if(flags & ITEM_SLOT_GLOVES) owner.update_inv_gloves() if(flags & ITEM_SLOT_EYES) owner.update_inv_glasses() if(flags & ITEM_SLOT_EARS) owner.update_inv_ears() if(flags & ITEM_SLOT_MASK) owner.update_inv_wear_mask() if(flags & ITEM_SLOT_HEAD) owner.update_inv_head() if(flags & ITEM_SLOT_FEET) owner.update_inv_shoes() if(flags & ITEM_SLOT_ID) owner.update_inv_wear_id() if(flags & ITEM_SLOT_BELT) owner.update_inv_belt() if(flags & ITEM_SLOT_BACK) owner.update_inv_back() if(flags & ITEM_SLOT_NECK) owner.update_inv_neck() ///Returns the temperature of src. If you want to know if an item is hot use this proc. /obj/item/proc/get_temperature() return heat ///Returns the sharpness of src. If you want to get the sharpness of an item use this. /obj/item/proc/get_sharpness() return sharpness /obj/item/proc/get_dismemberment_chance(obj/item/bodypart/affecting) if(affecting.can_dismember(src)) if((sharpness || damtype == BURN) && w_class >= WEIGHT_CLASS_NORMAL && force >= 10) . = force * (affecting.get_damage() / affecting.max_damage) /obj/item/proc/get_dismember_sound() if(damtype == BURN) . = 'sound/weapons/sear.ogg' else . = "desceration" /obj/item/proc/open_flame(flame_heat=700) var/turf/location = loc if(ismob(location)) var/mob/M = location var/success = FALSE if(src == M.get_item_by_slot(ITEM_SLOT_MASK)) success = TRUE if(success) location = get_turf(M) if(isturf(location)) location.hotspot_expose(flame_heat, 5) /obj/item/proc/ignition_effect(atom/A, mob/user) if(get_temperature()) . = "[user] lights [A] with [src]." else . = "" /obj/item/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum) return /obj/item/attack_hulk(mob/living/carbon/human/user) return FALSE /obj/item/attack_animal(mob/living/simple_animal/M) if (obj_flags & CAN_BE_HIT) return ..() return 0 /obj/item/mech_melee_attack(obj/mecha/M) return 0 /obj/item/burn() if(!QDELETED(src)) var/turf/T = get_turf(src) var/ash_type = /obj/effect/decal/cleanable/ash if(w_class == WEIGHT_CLASS_HUGE || w_class == WEIGHT_CLASS_GIGANTIC) ash_type = /obj/effect/decal/cleanable/ash/large var/obj/effect/decal/cleanable/ash/A = new ash_type(T) A.desc += "\nLooks like this used to be \an [name] some time ago." ..() /obj/item/acid_melt() if(!QDELETED(src)) var/turf/T = get_turf(src) var/obj/effect/decal/cleanable/molten_object/MO = new(T) MO.pixel_x = rand(-16,16) MO.pixel_y = rand(-16,16) MO.desc = "Looks like this was \an [src] some time ago." ..() /obj/item/proc/microwave_act(obj/machinery/microwave/M) SEND_SIGNAL(src, COMSIG_ITEM_MICROWAVE_ACT, M) if(istype(M) && M.dirty < 100) M.dirty++ /obj/item/proc/on_mob_death(mob/living/L, gibbed) /obj/item/proc/grind_requirements(obj/machinery/reagentgrinder/R) //Used to check for extra requirements for grinding an object return TRUE ///Called BEFORE the object is ground up - use this to change grind results based on conditions. Use "return -1" to prevent the grinding from occurring /obj/item/proc/on_grind() /obj/item/proc/on_juice() /obj/item/proc/set_force_string() switch(force) if(0 to 4) force_string = "very low" if(4 to 7) force_string = "low" if(7 to 10) force_string = "medium" if(10 to 11) force_string = "high" if(11 to 20) //12 is the force of a toolbox force_string = "robust" if(20 to 25) force_string = "very robust" else force_string = "exceptionally robust" last_force_string_check = force /obj/item/proc/openTip(location, control, params, user) if(last_force_string_check != force && !(item_flags & FORCE_STRING_OVERRIDE)) set_force_string() if(!(item_flags & FORCE_STRING_OVERRIDE)) openToolTip(user,src,params,title = name,content = "[desc]
[force ? "Force: [force_string]" : ""]",theme = "") else openToolTip(user,src,params,title = name,content = "[desc]
Force: [force_string]",theme = "") /obj/item/MouseEntered(location, control, params) if((item_flags & IN_INVENTORY || item_flags & IN_STORAGE) && usr.client.prefs.enable_tips && !QDELETED(src)) var/timedelay = usr.client.prefs.tip_delay/100 var/user = usr tip_timer = addtimer(CALLBACK(src, .proc/openTip, location, control, params, user), timedelay, TIMER_STOPPABLE)//timer takes delay in deciseconds, but the pref is in milliseconds. dividing by 100 converts it. /obj/item/MouseExited() deltimer(tip_timer)//delete any in-progress timer if the mouse is moved off the item before it finishes closeToolTip(usr) /// Called when a mob tries to use the item as a tool.Handles most checks. /obj/item/proc/use_tool(atom/target, mob/living/user, delay, amount=0, volume=0, datum/callback/extra_checks) // No delay means there is no start message, and no reason to call tool_start_check before use_tool. // Run the start check here so we wouldn't have to call it manually. if(!delay && !tool_start_check(user, amount)) return var/skill_modifier = 1 if(tool_behaviour == TOOL_MINING && ishuman(user)) var/mob/living/carbon/human/H = user skill_modifier = H.mind.get_skill_modifier(/datum/skill/mining, SKILL_SPEED_MODIFIER) if(H.mind.get_skill_level(/datum/skill/mining) >= SKILL_LEVEL_JOURNEYMAN && prob(H.mind.get_skill_modifier(/datum/skill/mining, SKILL_PROBS_MODIFIER))) // we check if the skill level is greater than Journeyman and then we check for the probality for that specific level. mineral_scan_pulse(get_turf(H), SKILL_LEVEL_JOURNEYMAN - 2) //SKILL_LEVEL_JOURNEYMAN = 3 So to get range of 1+ we have to subtract 2 from it,. delay *= toolspeed * skill_modifier // Play tool sound at the beginning of tool usage. play_tool_sound(target, volume) if(delay) // Create a callback with checks that would be called every tick by do_after. var/datum/callback/tool_check = CALLBACK(src, .proc/tool_check_callback, user, amount, extra_checks) if(ismob(target)) if(!do_mob(user, target, delay, extra_checks=tool_check)) return else if(!do_after(user, delay, target=target, extra_checks=tool_check)) return else // Invoke the extra checks once, just in case. if(extra_checks && !extra_checks.Invoke()) return // Use tool's fuel, stack sheets or charges if amount is set. if(amount && !use(amount)) return // Play tool sound at the end of tool usage, // but only if the delay between the beginning and the end is not too small if(delay >= MIN_TOOL_SOUND_DELAY) play_tool_sound(target, volume) return TRUE /// Called before [obj/item/proc/use_tool] if there is a delay, or by [obj/item/proc/use_tool] if there isn't. Only ever used by welding tools and stacks, so it's not added on any other [obj/item/proc/use_tool] checks. /obj/item/proc/tool_start_check(mob/living/user, amount=0) . = tool_use_check(user, amount) if(.) SEND_SIGNAL(src, COMSIG_TOOL_START_USE, user) /// A check called by [/obj/item/proc/tool_start_check] once, and by use_tool on every tick of delay. /obj/item/proc/tool_use_check(mob/living/user, amount) return !amount /// Generic use proc. Depending on the item, it uses up fuel, charges, sheets, etc. Returns TRUE on success, FALSE on failure. /obj/item/proc/use(used) return !used /// Plays item's usesound, if any. /obj/item/proc/play_tool_sound(atom/target, volume=50) if(target && usesound && volume) var/played_sound = usesound if(islist(usesound)) played_sound = pick(usesound) playsound(target, played_sound, volume, TRUE) /// Used in a callback that is passed by use_tool into do_after call. Do not override, do not call manually. /obj/item/proc/tool_check_callback(mob/living/user, amount, datum/callback/extra_checks) SHOULD_NOT_OVERRIDE(TRUE) . = tool_use_check(user, amount) && (!extra_checks || extra_checks.Invoke()) if(.) SEND_SIGNAL(src, COMSIG_TOOL_IN_USE, user) /// Returns a numeric value for sorting items used as parts in machines, so they can be replaced by the rped /obj/item/proc/get_part_rating() return 0 /obj/item/doMove(atom/destination) if (ismob(loc)) var/mob/M = loc var/hand_index = M.get_held_index_of_item(src) if(hand_index) M.held_items[hand_index] = null M.update_inv_hands() if(M.client) M.client.screen -= src layer = initial(layer) plane = initial(plane) appearance_flags &= ~NO_CLIENT_COLOR dropped(M, FALSE) return ..() /obj/item/proc/embedded(mob/living/carbon/human/embedded_mob) return /obj/item/proc/unembedded() if(item_flags & DROPDEL) QDEL_NULL(src) return TRUE /obj/item/proc/canStrip(mob/stripper, mob/owner) SHOULD_BE_PURE(TRUE) return !HAS_TRAIT(src, TRAIT_NODROP) /obj/item/proc/doStrip(mob/stripper, mob/owner) return owner.dropItemToGround(src) ///Does the current embedding var meet the criteria for being harmless? Namely, does it have a pain multiplier and jostle pain mult of 0? If so, return true. /obj/item/proc/isEmbedHarmless() if(embedding) return !isnull(embedding["pain_mult"]) && !isnull(embedding["jostle_pain_mult"]) && embedding["pain_mult"] == 0 && embedding["jostle_pain_mult"] == 0 ///In case we want to do something special (like self delete) upon failing to embed in something, return true /obj/item/proc/failedEmbed() if(item_flags & DROPDEL) QDEL_NULL(src) return TRUE ///Called by the carbon throw_item() proc. Returns null if the item negates the throw, or a reference to the thing to suffer the throw else. /obj/item/proc/on_thrown(mob/living/carbon/user, atom/target) if((item_flags & ABSTRACT) || HAS_TRAIT(src, TRAIT_NODROP)) return user.dropItemToGround(src, silent = TRUE) if(throwforce && HAS_TRAIT(user, TRAIT_PACIFISM)) to_chat(user, "You set [src] down gently on the ground.") return return src /** * tryEmbed() is for when you want to try embedding something without dealing with the damage + hit messages of calling hitby() on the item while targetting the target. * * Really, this is used mostly with projectiles with shrapnel payloads, from [/datum/element/embed/proc/checkEmbedProjectile], and called on said shrapnel. Mostly acts as an intermediate between different embed elements. * * Arguments: * * target- Either a body part, a carbon, or a closed turf. What are we hitting? * * forced- Do we want this to go through 100%? */ /obj/item/proc/tryEmbed(atom/target, forced=FALSE, silent=FALSE) if(!isbodypart(target) && !iscarbon(target) && !isclosedturf(target)) return if(!forced && !LAZYLEN(embedding)) return if(SEND_SIGNAL(src, COMSIG_EMBED_TRY_FORCE, target, forced, silent)) return TRUE failedEmbed() ///For when you want to disable an item's embedding capabilities (like transforming weapons and such), this proc will detach any active embed elements from it. /obj/item/proc/disableEmbedding() SEND_SIGNAL(src, COMSIG_ITEM_DISABLE_EMBED) return ///For when you want to add/update the embedding on an item. Uses the vars in [/obj/item/embedding], and defaults to config values for values that aren't set. Will automatically detach previous embed elements on this item. /obj/item/proc/updateEmbedding() if(!islist(embedding) || !LAZYLEN(embedding)) return AddElement(/datum/element/embed,\ embed_chance = (!isnull(embedding["embed_chance"]) ? embedding["embed_chance"] : EMBED_CHANCE),\ fall_chance = (!isnull(embedding["fall_chance"]) ? embedding["fall_chance"] : EMBEDDED_ITEM_FALLOUT),\ pain_chance = (!isnull(embedding["pain_chance"]) ? embedding["pain_chance"] : EMBEDDED_PAIN_CHANCE),\ pain_mult = (!isnull(embedding["pain_mult"]) ? embedding["pain_mult"] : EMBEDDED_PAIN_MULTIPLIER),\ remove_pain_mult = (!isnull(embedding["remove_pain_mult"]) ? embedding["remove_pain_mult"] : EMBEDDED_UNSAFE_REMOVAL_PAIN_MULTIPLIER),\ rip_time = (!isnull(embedding["rip_time"]) ? embedding["rip_time"] : EMBEDDED_UNSAFE_REMOVAL_TIME),\ ignore_throwspeed_threshold = (!isnull(embedding["ignore_throwspeed_threshold"]) ? embedding["ignore_throwspeed_threshold"] : FALSE),\ impact_pain_mult = (!isnull(embedding["impact_pain_mult"]) ? embedding["impact_pain_mult"] : EMBEDDED_IMPACT_PAIN_MULTIPLIER),\ jostle_chance = (!isnull(embedding["jostle_chance"]) ? embedding["jostle_chance"] : EMBEDDED_JOSTLE_CHANCE),\ jostle_pain_mult = (!isnull(embedding["jostle_pain_mult"]) ? embedding["jostle_pain_mult"] : EMBEDDED_JOSTLE_PAIN_MULTIPLIER),\ pain_stam_pct = (!isnull(embedding["pain_stam_pct"]) ? embedding["pain_stam_pct"] : EMBEDDED_PAIN_STAM_PCT),\ embed_chance_turf_mod = (!isnull(embedding["embed_chance_turf_mod"]) ? embedding["embed_chance_turf_mod"] : EMBED_CHANCE_TURF_MOD)) return TRUE