Files
Paradise/code/game/objects/items.dm
Tigercat2000 aa3b7ac678 -tg- screen alerts
A lot has changed.

Major points:
 - All mobs now use the -tg- thrown alerts system. This is a system where
   a maximum of 5 "alerts" (which take the apperance of HUD icons like the
   inventory and modular action buttons) on their HUD.
 - Alerts are defined as a subtype of /obj/screen/alert.
   - Alerts are "thrown", or activated on the mob with the proc
     `mob.throw_alert("alert_id", /obj/screen/alert/path, severity
     (optional), new_master (optional, overlays the referenced "obj" on the
     button))`
   - Alerts are cleared by calling `mob.clear_alert("alert_id")` or by the
     /obj/screen/alert containing a `timeout` setting, which will
     automatically clear itself after that period of deciseconds.
   - Alerts may have functionality beyond appearance: Mousing over them
     will use the WireWraith tooltip system to generate a themed tooltip,
     and clicking them may have a function defined on the
     /obj/screen/alert object.
   - Shift-clicking an alert will give you it's name and status, in case
     the tooltips fail to work.

 - Hunger/Oxygen/Toxin/Nitrogen/Pressure/Etc warnings are now handled via
   the -tg- thrown alerts system.
   - Failing to breathe anything will display as an "No O2" warning.
   - Species breathing has been refactored to accomodate this. Vox are
     able to breathe the station air without instantly dying, but will be
     poisoned every time they breathe by the oxygen in the air. Any
     species with a unique gas breathing type will also display the
     correct "Choking (no X gas)" instead of just "oxygen". (Unless they
     have not breathed anything in, it's a quirk.)
   - Robot cell/temperature alerts also use this.
   - Aliens, though not harmed by toxins, will have an alert if they
     breathe in toxins, notifying them that "You'll be toast if this
     lights up."

 - More alerts have been added
   - Buckling
     - Activated on: Being buckled to an object.
     - Cleared on: Being unbuckled.
     - Click functionality: Calls resist(); Will unbuckle from chair
       instantly if unrestrained, otherwise, there is a delay period.
   - Hand/Leg cuffs
     - Activated on: Being handcuffed.
     - Cleared on: Being unhandcuffed.
     - Click functionality: Calls resist(); Will attempt to either get out
       of the handcuffs, or, if you are a xenomorph or hulk, break the
       handcuffs in 5 seconds.
   - Blind/High
     - Activated on: Becoming blinded/becoming high on LSD.
     - Cleared on: Becoming unblinded/the high wearing off.
     - Click functionality: None.
   - Asleep
     - Activated on: Life() tick detecting sleeping.
     - Deactivated on: Sleeping being 0 or less.
     - Click functionality: None.
   - Weightless
     - Activated on: Losing gravity.
     - Deactivated on: Moving back into an area with gravity.
     - Click functionality: None.
   - On Fire
     - Activated on: Catching fire.
     - Deactivated on: Being extinguished.
     - Click functionality: Calls resist(); Causes you to stop, drop, and
       roll, which will reduce firestacks and possibly extinguish you.
   - Law update (BORG ONLY)
     - Activated on: Laws being changed.
     - Deactivated on: Timer, 300 deciseconds.
     - Click functionality: None.
   - Hacked (BORG ONLY)
     - Activated on: Being emagged/given malf tools by the malf AI.
     - Deactivated on: Emagged status being removed.
     - Click functionality: None.
   - Locked (BORG ONLY)
     - Activated on: Lockdown being set (by emag law rewriting/robotics
       console/wire being destroyed)
     - Deactivated on: Movement being unlocked.
     - Click functionality: None.
   - Notify Cloning (GHOST ONLY)
     - Activated on: A human's body being placed in a DNA scanner.
     - Deactivated on: Timer, 300 deciseconds.
     - Click functionality: Reenters body.
   - Notify Jump (MULTIPURPOSE) (GHOST ONLY)
     - Activated on: Any sort of chance to become a mob (ie, golem rune).
     - Deactivated on: Timer, 300 deciseconds.
     - Click functionality: Varies.
2016-04-16 14:27:03 -07:00

526 lines
19 KiB
Plaintext

/obj/item
name = "item"
icon = 'icons/obj/items.dmi'
var/discrete = 0 // used in item_attack.dm to make an item not show an attack message to viewers
var/no_embed = 0 // For use in item_attack.dm
var/image/blood_overlay = null //this saves our blood splatter overlay, which will be processed not to go over the edges of the sprite
var/blood_overlay_color = null
var/item_state = null
var/lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
var/righthand_file = 'icons/mob/inhands/items_righthand.dmi'
//Dimensions of the lefthand_file and righthand_file vars
//eg: 32x32 sprite, 64x64 sprite, etc.
var/inhand_x_dimension = 32
var/inhand_y_dimension = 32
var/r_speed = 1.0
var/health = null
var/hitsound = null
var/w_class = 3.0
var/slot_flags = 0 //This is used to determine on which slots an item can fit.
pass_flags = PASSTABLE
pressure_resistance = 3
// causeerrorheresoifixthis
var/obj/item/master = null
var/heat_protection = 0 //flags which determine which body parts are protected from heat. Use the HEAD, UPPER_TORSO, LOWER_TORSO, etc. flags. See setup.dm
var/cold_protection = 0 //flags which determine which body parts are protected from cold. Use the HEAD, UPPER_TORSO, LOWER_TORSO, etc. flags. See setup.dm
var/max_heat_protection_temperature //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/min_cold_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
//If this is set, The item will make an action button on the player's HUD when picked up.
var/action_button_name //It is also the text which gets displayed on the action button. If not set it defaults to 'Use [name]'. If it's not set, there'll be no button.
var/action_button_is_hands_free = 0 //If 1, bypass the restrained, lying, and stunned checks action buttons normally test for
var/datum/action/item_action/action = null
var/list/materials = list()
//Since any item can now be a piece of clothing, this has to be put here so all items share it.
var/flags_inv //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/item_color = null
var/body_parts_covered = 0 //see setup.dm for appropriate bit flags
//var/heat_transfer_coefficient = 1 //0 prevents all transfers, 1 is invisible
var/gas_transfer_coefficient = 1 // for leaking gas from turf to mask and vice-versa (for masks right now, but at some point, i'd like to include space helmets)
var/permeability_coefficient = 1 // for chemicals/diseases
var/siemens_coefficient = 1 // for electrical admittance/conductance (electrocution checks and shit)
var/slowdown = 0 // How much clothing is slowing you down. Negative values speeds you up
var/armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
var/armour_penetration = 0 //percentage of armour effectiveness to remove
var/list/allowed = null //suit storage stuff.
var/obj/item/device/uplink/hidden/hidden_uplink = null // All items can have an uplink hidden inside, just remember to add the triggers.
var/needs_permit = 0 //Used by security bots to determine if this item is safe for public use.
var/strip_delay = DEFAULT_ITEM_STRIP_DELAY
var/put_on_delay = DEFAULT_ITEM_PUTON_DELAY
var/breakouttime = 0
/* Species-specific sprites, concept stolen from Paradise//vg/.
ex:
sprite_sheets = list(
"Tajaran" = 'icons/cat/are/bad'
)
If index term exists and icon_override is not set, this sprite sheet will be used.
*/
var/list/sprite_sheets = null
var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc.
var/sprite_sheets_obj = null //Used to override hardcoded clothing inventory object dmis in human clothing proc.
var/list/species_fit = null //This object has a different appearance when worn by these species
/obj/item/Destroy()
if(ismob(loc))
var/mob/m = loc
m.unEquip(src, 1)
return ..()
/obj/item/proc/check_allowed_items(atom/target, not_inside, target_self)
if(((src in target) && !target_self) || ((!istype(target.loc, /turf)) && (!istype(target, /turf)) && (not_inside)))
return 0
else
return 1
/obj/item/device
icon = 'icons/obj/device.dmi'
/obj/item/ex_act(severity)
switch(severity)
if(1.0)
qdel(src)
return
if(2.0)
if (prob(50))
qdel(src)
return
if(3.0)
if (prob(5))
qdel(src)
return
else
return
/obj/item/blob_act()
qdel(src)
//user: The mob that is suiciding
//damagetype: The type of damage the item will inflict on the user
//BRUTELOSS = 1
//FIRELOSS = 2
//TOXLOSS = 4
//OXYLOSS = 8
//Output a creative message and then return the damagetype done
/obj/item/proc/suicide_act(mob/user)
return
/obj/item/verb/move_to_top()
set name = "Move To Top"
set category = null
set src in oview(1)
if(!istype(src.loc, /turf) || usr.stat || usr.restrained() )
return
var/turf/T = src.loc
src.loc = null
src.loc = T
/obj/item/examine(mob/user, var/distance = -1)
var/size
switch(src.w_class)
if(1.0)
size = "tiny"
if(2.0)
size = "small"
if(3.0)
size = "normal-sized"
if(4.0)
size = "bulky"
if(5.0)
size = "huge"
. = ..(user, distance, "", "It is a [size] item.")
if(user.research_scanner) //Mob has a research scanner active.
var/msg = "*--------* <BR>"
if(origin_tech)
msg += "<span class='notice'>Testing potentials:</span><BR>"
var/list/techlvls = params2list(origin_tech)
for(var/T in techlvls) //This needs to use the better names.
msg += "Tech: [CallTechName(T)] | Magnitude: [techlvls[T]] <BR>"
msg += "Research reliability: [reliability]% <BR>"
if(crit_fail)
msg += "<span class='danger'>Critical failure detected in subject!</span><BR>"
else
msg += "<span class='danger'>No tech origins detected.</span><BR>"
if(materials.len)
msg += "<span class='notice'>Extractable materials:<BR>"
for(var/mat in materials)
msg += "[CallMaterialName(mat)]<BR>" //Capitize first word, remove the "$"
else
msg += "<span class='danger'>No extractable materials detected.</span><BR>"
msg += "*--------*"
to_chat(user, msg)
/obj/item/attack_hand(mob/user as mob)
if (!user) return 0
if (hasorgans(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/temp = H.organs_by_name["r_hand"]
if (user.hand)
temp = H.organs_by_name["l_hand"]
if(!temp)
to_chat(user, "<span class='warning'>You try to use your hand, but it's missing!</span>")
return 0
if(temp && !temp.is_usable())
to_chat(user, "<span class='warning'>You try to move your [temp.name], but cannot!</span>")
return 0
if (istype(src.loc, /obj/item/weapon/storage))
//If the item is in a storage item, take it out
var/obj/item/weapon/storage/S = src.loc
S.remove_from_storage(src)
src.throwing = 0
if (loc == user)
if(!user.unEquip(src))
return 0
else
if(isliving(loc))
return 0
pickup(user)
add_fingerprint(user)
user.put_in_active_hand(src)
return 1
/obj/item/attack_alien(mob/user as mob)
if(isalien(user)) // -- TLE
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.unEquip(src)
to_chat(user, "Your claws aren't capable of such fine manipulation.")
return
if (istype(src.loc, /obj/item/weapon/storage))
for(var/mob/M in range(1, src.loc))
if (M.s_active == src.loc)
if (M.client)
M.client.screen -= src
src.throwing = 0
if (src.loc == user)
if(!user.unEquip(src))
return
else
if(istype(src.loc, /mob/living))
return
src.pickup(user)
user.put_in_active_hand(src)
return
/obj/item/attack_alien(mob/user as mob)
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.unEquip(src)
to_chat(user, "Your claws aren't capable of such fine manipulation.")
return
attack_hand(A)
/obj/item/attack_ai(mob/user as mob)
if (istype(src.loc, /obj/item/weapon/robot_module))
//If the item is part of a cyborg module, equip it
if(!isrobot(user)) return
var/mob/living/silicon/robot/R = user
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
/obj/item/attackby(obj/item/weapon/W as obj, mob/user as mob, params)
if(istype(W,/obj/item/weapon/storage))
var/obj/item/weapon/storage/S = W
if(S.use_to_pickup)
if(S.collection_mode) //Mode is set to collect all items on a tile and we clicked on a valid one.
if(isturf(src.loc))
var/list/rejections = list()
var/success = 0
var/failure = 0
for(var/obj/item/I in src.loc)
if(I.type in rejections) // To limit bag spamming: any given type only complains once
continue
if(!S.can_be_inserted(I)) // Note can_be_inserted still makes noise when the answer is no
rejections += I.type // therefore full bags are still a little spammy
failure = 1
continue
success = 1
S.handle_item_insertion(I, 1) //The 1 stops the "You put the [src] into [S]" insertion message from being displayed.
if(success && !failure)
to_chat(user, "<span class='notice'>You put everything in [S].</span>")
else if(success)
to_chat(user, "<span class='notice'>You put some things in [S].</span>")
else
to_chat(user, "<span class='notice'>You fail to pick anything up with [S].</span>")
else if(S.can_be_inserted(src))
S.handle_item_insertion(src)
return
/obj/item/proc/talk_into(mob/M as mob, var/text, var/channel=null)
return
/obj/item/proc/moved(mob/user as mob, old_loc as turf)
return
/obj/item/proc/dropped(mob/user as mob)
..()
// called just as an item is picked up (loc is not yet changed)
/obj/item/proc/pickup(mob/user)
return
// 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/weapon/storage/S as obj)
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/weapon/storage/S as obj)
return
// called when "found" in pockets and storage items. Returns 1 if the search should end.
/obj/item/proc/on_found(mob/finder as mob)
return
// called after an item is placed in an equipment slot
// 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
// note this isn't called during the initial dressing of a player
/obj/item/proc/equipped(var/mob/user, var/slot)
return
//returns 1 if the item is equipped by a mob, 0 otherwise.
//This might need some error trapping, not sure if get_equipped_items() is safe for non-human mobs.
/obj/item/proc/is_equipped()
if(!ismob(loc))
return 0
var/mob/M = loc
if(src in M.get_equipped_items())
return 1
else
return 0
//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 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.
//Set disable_warning to 1 if you wish it to not give you outputs.
/obj/item/proc/mob_can_equip(mob/M, slot, disable_warning = 0)
if(!M)
return 0
return M.can_equip(src, slot, disable_warning)
/obj/item/verb/verb_pickup()
set src in oview(1)
set category = null
set name = "Pick up"
if(!(usr)) //BS12 EDIT
return
if(!usr.canmove || usr.stat || usr.restrained() || !Adjacent(usr))
return
if((!istype(usr, /mob/living/carbon)) || (istype(usr, /mob/living/carbon/brain)))//Is humanoid, and is not a brain
to_chat(usr, "\red You can't pick things up!")
return
if( usr.stat || usr.restrained() )//Is not asleep/dead and is not restrained
to_chat(usr, "\red You can't pick things up!")
return
if(src.anchored) //Object isn't anchored
to_chat(usr, "\red You can't pick that up!")
return
if(!usr.hand && usr.r_hand) //Right hand is not full
to_chat(usr, "\red Your right hand is full.")
return
if(usr.hand && usr.l_hand) //Left hand is not full
to_chat(usr, "\red Your left hand is full.")
return
if(!istype(src.loc, /turf)) //Object is on a turf
to_chat(usr, "\red You can't pick that up!")
return
//All checks are done, time to pick it up!
usr.UnarmedAttack(src)
return
//This proc is executed when someone clicks the on-screen UI button. To make the UI button show, set the 'icon_action_button' to the icon_state of the image of the button in screen1_action.dmi
//The default action is attack_self().
//Checks before we get to here are: mob is alive, mob is not restrained, paralyzed, asleep, resting, laying, item is on the mob.
/obj/item/proc/ui_action_click()
attack_self(usr)
/obj/item/proc/IsShield()
return 0
/obj/item/proc/IsReflect(var/def_zone) //This proc determines if and at what% an object will reflect energy projectiles if it's in l_hand,r_hand or wear_suit
return 0
/obj/item/proc/get_loc_turf()
var/atom/L = loc
while(L && !istype(L, /turf/))
L = L.loc
return loc
/obj/item/proc/eyestab(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
var/mob/living/carbon/human/H = M
if(istype(H) && ( \
(H.head && H.head.flags & HEADCOVERSEYES) || \
(H.wear_mask && H.wear_mask.flags & MASKCOVERSEYES) || \
(H.glasses && H.glasses.flags & GLASSESCOVERSEYES) \
))
// you can't stab someone in the eyes wearing a mask!
to_chat(user, "<span class='danger'>You're going to need to remove that mask/helmet/glasses first!</span>")
return
if(istype(M, /mob/living/carbon/alien) || istype(M, /mob/living/carbon/slime))//Aliens don't have eyes./N slimes also don't have eyes!
to_chat(user, "<span class='warning'>You cannot locate any eyes on this creature!</span>")
return
if(!iscarbon(user))
M.LAssailant = null
else
M.LAssailant = user
src.add_fingerprint(user)
playsound(loc, src.hitsound, 30, 1, -1)
if(M != user)
M.visible_message("<span class='danger'>[user] has stabbed [M] in the eye with [src]!</span>", \
"<span class='userdanger'>[user] stabs you in the eye with [src]!</span>")
user.do_attack_animation(M)
else
user.visible_message( \
"<span class='danger'>[user] has stabbed themself in the eyes with [src]!</span>", \
"<span class='userdanger'>You stab yourself in the eyes with [src]!</span>" \
)
add_logs(M, user, "attacked", "[src.name]", "(INTENT: [uppertext(user.a_intent)])")
if(istype(H))
var/obj/item/organ/internal/eyes/eyes = H.get_int_organ(/obj/item/organ/internal/eyes)
if(!eyes) // should still get stabbed in the head
var/obj/item/organ/external/head/head = H.organs_by_name["head"]
head.take_damage(rand(10,14), 1)
return
eyes.take_damage(rand(3,4), 1)
if(eyes.damage >= eyes.min_bruised_damage)
if(M.stat != 2)
if(!(eyes.status & ORGAN_ROBOT) || !(eyes.status & ORGAN_ASSISTED)) //robot eyes bleeding might be a bit silly
to_chat(M, "<span class='danger'>Your eyes start to bleed profusely!</span>")
if(prob(50))
if(M.stat != 2)
to_chat(M, "<span class='danger'>You drop what you're holding and clutch at your eyes!</span>")
M.drop_item()
M.eye_blurry += 10
M.Paralyse(1)
M.Weaken(2)
if (eyes.damage >= eyes.min_broken_damage)
if(M.stat != 2)
to_chat(M, "<span class='danger'>You go blind!</span>")
var/obj/item/organ/external/affecting = H.get_organ("head")
if(affecting.take_damage(7))
H.UpdateDamageIcon()
else
M.take_organ_damage(7)
M.eye_blurry += rand(3,4)
return
/obj/item/clean_blood()
. = ..()
if(blood_overlay)
overlays.Remove(blood_overlay)
if(istype(src, /obj/item/clothing/gloves))
var/obj/item/clothing/gloves/G = src
G.transfer_blood = 0
/obj/item/add_blood(mob/living/carbon/human/M as mob)
if (!..())
return 0
if(istype(src, /obj/item/weapon/melee/energy))
return
//if we haven't made our blood_overlay already
if( !blood_overlay )
generate_blood_overlay()
//apply the blood-splatter overlay if it isn't already in there
if(!blood_DNA.len)
blood_overlay.color = blood_color
overlays += blood_overlay
//if this blood isn't already in the list, add it
if(istype(M))
if(blood_DNA[M.dna.unique_enzymes])
return 0 //already bloodied with this blood. Cannot add more.
blood_DNA[M.dna.unique_enzymes] = M.dna.b_type
return 1 //we applied blood to the item
/obj/item/proc/generate_blood_overlay()
if(blood_overlay)
return
var/icon/I = new /icon(icon, icon_state)
I.Blend(new /icon('icons/effects/blood.dmi', rgb(255,255,255)),ICON_ADD) //fills the icon_state with white (except where it's transparent)
I.Blend(new /icon('icons/effects/blood.dmi', "itemblood"),ICON_MULTIPLY) //adds blood and the remaining white areas become transparant
//not sure if this is worth it. It attaches the blood_overlay to every item of the same type if they don't have one already made.
for(var/obj/item/A in world)
if(A.type == type && !A.blood_overlay)
A.blood_overlay = image(I)
/obj/item/singularity_pull(S, current_size)
spawn(0) //this is needed or multiple items will be thrown sequentially and not simultaneously
if(current_size >= STAGE_FOUR)
throw_at(S,14,3)
else ..()
/obj/item/proc/pwr_drain()
return 0 // Process Kill
/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/weapon/storage
if(!newLoc)
return 0
if(istype(loc,/obj/item/weapon/storage))
var/obj/item/weapon/storage/S = loc
S.remove_from_storage(src,newLoc)
return 1
return 0
/obj/item/proc/wash(mob/user, atom/source)
if(flags & ABSTRACT) //Abstract items like grabs won't wash. No-drop items will though because it's still technically an item in your hand.
return
to_chat(user, "<span class='notice'>You start washing [src]...</span>")
if(!do_after(user, 40, target = source))
return
clean_blood()
user.visible_message("<span class='notice'>[user] washes [src] using [source].</span>", \
"<span class='notice'>You wash [src] using [source].</span>")
return 1