Files
30fbcfe9b4 Belts & Trashbags (#7443)
requires #6644 

Entirely replaces how (most) belts perform insertion checks.

This pretty much allows belts to hold most things.

Armor vests are next.

Trashbags will also use the systems we use on main.

Closes #7256 and #7435

---------

Co-authored-by: silicons <silicons@silicons.dev>
2025-12-28 22:05:06 -05:00

466 lines
14 KiB
Plaintext

/obj/item/flashlight
name = "flashlight"
desc = "A hand-held emergency light."
icon = 'icons/obj/lighting.dmi'
icon_state = "flashlight"
w_class = WEIGHT_CLASS_SMALL
slot_flags = SLOT_BELT
materials_base = list(MAT_STEEL = 50, MAT_GLASS = 20)
item_action_name = "Toggle Flashlight"
light_wedge = LIGHT_WIDE
worth_intrinsic = 25
suit_storage_class = SUIT_STORAGE_CLASS_SOFTWEAR | SUIT_STORAGE_CLASS_HARDWEAR
belt_storage_class = BELT_CLASS_MEDIUM
belt_storage_size = BELT_SIZE_FOR_FLASHLIGHT
var/on = FALSE
/// Luminosity when on
var/brightness_on = 4
/// Lighting power when on
var/flashlight_power = 0.8
/// Range of light when on, can be negative.
var/flashlight_range = 4
var/cell_type = /obj/item/cell/basic/tier_1/small
var/cell_accept = CELL_TYPE_SMALL | CELL_TYPE_WEAPON
var/list/brightness_levels
var/brightness_level = "medium"
var/power_usage
var/power_use = 1
/// A way for mappers to force which way a flashlight faces upon spawning.
var/spawn_dir
/obj/item/flashlight/Initialize(mapload)
init_cell_slot_easy_tool(cell_type, cell_accept)
set_flashlight()
. = ..()
if(power_use)
brightness_levels = list("low" = 0.25, "medium" = 0.5, "high" = 1)
power_usage = brightness_levels[brightness_level]
else
remove_obj_verb(src, /obj/item/flashlight/verb/toggle)
update_appearance()
/obj/item/flashlight/Destroy()
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/flashlight/process(delta_time)
var/obj/item/cell/cell = obj_cell_slot?.cell
if(!on || !cell)
return PROCESS_KILL
if(brightness_level && power_usage)
if(cell.use(power_usage) != power_usage) //We weren't able to use our full power_usage amount!
visible_message(SPAN_WARNING("\The [src] flickers before going dull."))
set_light(FALSE)
playsound(src.loc, /datum/soundbyte/sparks, 10, 1, -3) //Small cue that your light went dull in your pocket.
on = FALSE
update_appearance()
return PROCESS_KILL
/obj/item/flashlight/verb/toggle()
set name = "Toggle Flashlight Brightness"
set category = VERB_CATEGORY_OBJECT
set src in usr
set_brightness(usr)
/obj/item/flashlight/proc/set_brightness(mob/user as mob)
var/choice = input("Choose a brightness level.") as null|anything in brightness_levels
if(choice)
brightness_level = choice
power_usage = brightness_levels[choice]
to_chat(user, SPAN_NOTICE("You set the brightness level on \the [src] to [brightness_level]."))
update_appearance()
/obj/item/flashlight/proc/set_flashlight()
if(light_wedge)
setDir(pick(NORTH, SOUTH, EAST, WEST))
if(spawn_dir)
setDir(spawn_dir)
if (on)
if(brightness_level == "low")
set_light(flashlight_range/2, flashlight_power*0.75, light_color)
else if(brightness_level == "high")
set_light(flashlight_range*1.5, flashlight_power*1.1, light_color)
else
set_light(flashlight_range, flashlight_power, light_color)
else
set_light(0)
/obj/item/flashlight/update_icon_state()
. = ..()
if(on)
icon_state = "[initial(icon_state)]-on"
else
icon_state = "[initial(icon_state)]"
/obj/item/flashlight/examine(mob/user, dist)
. = ..()
var/obj/item/cell/cell = obj_cell_slot?.cell
if(power_use && brightness_level)
. += "\The [src] is set to [brightness_level]. "
if(cell)
. += "\The [src] has a \the [cell] attached. "
if(cell.charge <= cell.max_charge*0.25)
. += "It appears to have a low amount of power remaining."
else if(cell.charge > cell.max_charge*0.25 && cell.charge <= cell.max_charge*0.5)
. += "It appears to have an average amount of power remaining."
else if(cell.charge > cell.max_charge*0.5 && cell.charge <= cell.max_charge*0.75)
. += "It appears to have an above average amount of power remaining."
else if(cell.charge > cell.max_charge*0.75 && cell.charge <= cell.max_charge)
. += "It appears to have a high amount of power remaining."
/obj/item/flashlight/AltClick(mob/user)
attack_self(user)
/obj/item/flashlight/attack_self(mob/user, datum/event_args/actor/actor)
var/obj/item/cell/cell = obj_cell_slot?.cell
if(power_use)
if(!isturf(user.loc))
to_chat(user, "You cannot turn the light on while in this [user.loc].") //To prevent some lighting anomalities.
return FALSE
if(!cell || cell.charge == 0)
to_chat(user, "You flick the switch on [src], but nothing happens.")
return FALSE
on = !on
if(on && power_use)
START_PROCESSING(SSobj, src)
else if(power_use)
STOP_PROCESSING(SSobj, src)
playsound(src.loc, 'sound/weapons/empty.ogg', 15, TRUE, -3)
set_flashlight()
update_full_icon()
return TRUE
/obj/item/flashlight/emp_act(severity)
for(var/obj/O in contents)
O.emp_act(severity)
..()
/obj/item/flashlight/legacy_mob_melee_hook(mob/target, mob/user, clickchain_flags, list/params, mult, target_zone, intent)
if(user.a_intent == INTENT_HARM)
return ..()
if(on && user.zone_sel.selecting == O_EYES && isliving(target))
var/mob/living/L = target
if((MUTATION_CLUMSY in user.mutations) && prob(50)) //too dumb to use flashlight properly
return ..() //just hit them in the head
var/mob/living/carbon/human/H = L //mob has protective eyewear
if(istype(H))
for(var/obj/item/C in H.inventory.query_coverage(EYES))
to_chat(user, SPAN_WARNING("You're going to need to remove [C.name] first."))
return
var/obj/item/organ/vision
if(H.species.vision_organ)
vision = H.internal_organs_by_name[H.species.vision_organ]
if(!vision)
to_chat(user, SPAN_WARNING("You can't find any [H.species.vision_organ ? H.species.vision_organ : "eyes"] on [H]!"))
user.visible_message(SPAN_NOTICE("\The [user] directs [src] to [L]'s eyes."), \
SPAN_NOTICE("You direct [src] to [L]'s eyes."))
if(H != user) //can't look into your own eyes buster
if(L.stat == DEAD || L.has_status_effect(/datum/status_effect/sight/blindness)) //mob is dead or fully blind
to_chat(user, SPAN_WARNING("\The [L]'s pupils do not react to the light!"))
return
if(MUTATION_XRAY in L.mutations)
to_chat(user, SPAN_NOTICE("\The [L] pupils give an eerie glow!"))
if(vision.is_bruised())
to_chat(user, SPAN_WARNING("There's visible damage to [L]'s [vision.name]!"))
else if(L.eye_blurry)
to_chat(user, SPAN_NOTICE("\The [L]'s pupils react slower than normally."))
if(L.getBrainLoss() > 15)
to_chat(user, SPAN_NOTICE("There's visible lag between left and right pupils' reactions."))
// todo: reagent effects.
var/static/list/reagents_that_cause_constriction = list(
/datum/reagent/tramadol,
/datum/reagent/oxycodone,
)
var/static/list/reagents_that_cause_dilation = list(
/datum/reagent/space_drugs,
/datum/reagent/mindbreaker,
)
if(L.reagents.has_any(reagents_that_cause_constriction) || H.ingested.has_any(reagents_that_cause_constriction))
to_chat(user, SPAN_NOTICE("\The [L]'s pupils are already pinpoint and cannot narrow any more."))
else if(L.reagents.has_any(reagents_that_cause_dilation) || H.ingested.has_any(reagents_that_cause_dilation))
to_chat(user, SPAN_NOTICE("\The [L]'s pupils narrow slightly, but are still very dilated."))
else
to_chat(user, SPAN_NOTICE("\The [L]'s pupils narrow."))
user.setClickCooldownLegacy(user.get_attack_speed_legacy(src)) //can be used offensively
L.flash_eyes()
return CLICKCHAIN_DO_NOT_PROPAGATE
return ..()
/obj/item/flashlight/pen
name = "penlight"
desc = "A pen-sized light, used by medical staff."
icon_state = "penlight"
item_state = "pen"
drop_sound = 'sound/items/drop/accessory.ogg'
pickup_sound = 'sound/items/pickup/accessory.ogg'
slot_flags = SLOT_EARS
brightness_on = 2
w_class = WEIGHT_CLASS_TINY
power_use = 0
flashlight_range = 2
light_wedge = LIGHT_OMNI
/obj/item/flashlight/color //Default color is blue, just roll with it.
name = "blue flashlight"
desc = "A hand-held emergency light. This one is blue."
icon_state = "flashlight_blue"
/obj/item/flashlight/color/red
name = "red flashlight"
desc = "A hand-held emergency light. This one is red."
icon_state = "flashlight_red"
/obj/item/flashlight/color/orange
name = "orange flashlight"
desc = "A hand-held emergency light. This one is orange."
icon_state = "flashlight_orange"
/obj/item/flashlight/color/yellow
name = "yellow flashlight"
desc = "A hand-held emergency light. This one is yellow."
icon_state = "flashlight_yellow"
/obj/item/flashlight/maglight
name = "maglight"
desc = "A very, very heavy duty flashlight."
icon_state = "maglight"
damage_force = 10
slot_flags = SLOT_BELT
w_class = WEIGHT_CLASS_SMALL
attack_verb = list ("smacked", "thwacked", "thunked")
attack_sound = "swing_hit"
materials_base = list(MAT_STEEL = 200, MAT_GLASS = 50)
light_color = LIGHT_COLOR_FLUORESCENT_FLASHLIGHT
light_wedge = LIGHT_NARROW
/// the gun attachment used for testing if we can attach
var/static/obj/item/gun_attachment/flashlight/maglight/test_attachment
/obj/item/flashlight/maglight/proc/get_test_attachment() as /obj/item/gun_attachment/flashlight/maglight
if(!test_attachment)
test_attachment = new
return test_attachment
/obj/item/flashlight/maglight/using_as_item(atom/target, datum/event_args/actor/clickchain/clickchain, clickchain_flags)
. = ..()
if(. & CLICKCHAIN_DO_NOT_PROPAGATE)
return
if(istype(target, /obj/item/gun))
var/obj/item/gun/gun_target = target
var/obj/item/gun_attachment/flashlight/maglight/test_attach = get_test_attachment()
if(gun_target.can_install_attachment(test_attach, clickchain))
if(!clickchain.performer.temporarily_remove_from_inventory(src))
clickchain.chat_feedback(SPAN_WARNING("[src] is stuck to your hands!"), src)
return CLICKCHAIN_DO_NOT_PROPAGATE
var/obj/item/gun_attachment/flashlight/maglight/attaching = new
if(!gun_target.install_attachment(attaching, clickchain))
CRASH("install failed after check")
else
attaching.our_maglight = src
forceMove(attaching)
return CLICKCHAIN_DO_NOT_PROPAGATE
/obj/item/flashlight/drone
name = "low-power flashlight"
desc = "A miniature lamp, that might be used by small robots."
icon_state = "penlight"
item_state = null
brightness_on = 2
flashlight_range = 2
w_class = WEIGHT_CLASS_TINY
power_use = 0
// the desk lamps are a bit special
/obj/item/flashlight/lamp
name = "desk lamp"
desc = "A desk lamp with an adjustable mount."
icon_state = "lamp"
damage_force = 10
brightness_on = 5
w_class = WEIGHT_CLASS_BULKY
power_use = 0
light_wedge = LIGHT_OMNI
light_color = LIGHT_COLOR_FIRE
flashlight_range = 4
/obj/item/flashlight/lamp/on
on = 1
// green-shaded desk lamp
/obj/item/flashlight/lamp/green
desc = "A classic green-shaded desk lamp."
icon_state = "lampgreen"
brightness_on = 5
light_color = LIGHT_COLOR_TUNGSTEN
/obj/item/flashlight/lamp/green/on
on = 1
/obj/item/flashlight/lamp/verb/toggle_light()
set name = "Toggle light"
set category = VERB_CATEGORY_OBJECT
set src in oview(1)
if(!usr.stat)
attack_self(usr)
// FLARES
/obj/item/flashlight/flare
name = "flare"
desc = "A red standard-issue flare. There are instructions on the side reading 'pull cord, make light'."
icon_state = "flare"
item_state = "flare"
w_class = WEIGHT_CLASS_SMALL
brightness_on = 8 // Pretty bright.
flashlight_power = 0.8
flashlight_range = 5
light_wedge = LIGHT_OMNI
light_color = LIGHT_COLOR_FLARE
item_action_name = null //just pull it manually, neckbeard.
power_use = 0
drop_sound = 'sound/items/drop/gloves.ogg'
pickup_sound = 'sound/items/pickup/gloves.ogg'
var/fuel = 0
var/on_damage = 7
var/produce_heat = 1500
/obj/item/flashlight/flare/Initialize(mapload)
. = ..()
fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.
/obj/item/flashlight/flare/process(delta_time)
var/turf/pos = get_turf(src)
if(pos)
pos.hotspot_expose(produce_heat, 5)
fuel = max(fuel - 1, 0)
if(!fuel || !on)
turn_off()
if(!fuel)
src.icon_state = "[initial(icon_state)]-empty"
STOP_PROCESSING(SSobj, src)
/obj/item/flashlight/flare/proc/turn_off()
on = FALSE
src.damage_force = initial(src.damage_force)
src.damage_type = initial(src.damage_type)
set_light(FALSE)
update_appearance()
/obj/item/flashlight/flare/attack_self(mob/user, datum/event_args/actor/actor)
// Usual checks
if(!fuel)
to_chat(user, SPAN_NOTICE("It's out of fuel."))
return
if(on)
return
. = ..()
// All good, turn it on.
if(.)
user.visible_message(SPAN_NOTICE("[user] activates the flare."), SPAN_NOTICE("You pull the cord on the flare, activating it!"))
src.damage_force = on_damage
src.damage_type = DAMAGE_TYPE_BURN
START_PROCESSING(SSobj, src)
/obj/item/flashlight/flare/proc/ignite() //Used for flare launchers.
on = !on
update_appearance()
damage_force = on_damage
damage_type = DAMAGE_TYPE_BURN
START_PROCESSING(SSobj, src)
return TRUE
/obj/item/flashlight/flare/survival
fuel = 15 MINUTES
//Glowsticks
/obj/item/flashlight/glowstick
name = "green glowstick"
desc = "A green military-grade glowstick."
w_class = WEIGHT_CLASS_SMALL
brightness_on = 4
icon_state = "glowstick"
item_state = "glowstick"
var/fuel = 0
power_use = 0
light_wedge = LIGHT_OMNI
light_color = LIGHT_COLOR_GREEN
flashlight_power = 0.9
flashlight_range = 3
/obj/item/flashlight/glowstick/Initialize(mapload)
. = ..()
fuel = rand(1600, 2000)
/obj/item/flashlight/glowstick/process(delta_time)
fuel = max(fuel - 1, 0)
if(!fuel || !on)
turn_off()
if(!fuel)
src.icon_state = "[initial(icon_state)]-empty"
STOP_PROCESSING(SSobj, src)
/obj/item/flashlight/glowstick/proc/turn_off()
on = FALSE
update_appearance()
/obj/item/flashlight/glowstick/attack_self(mob/user, datum/event_args/actor/actor)
if(!fuel)
to_chat(user, SPAN_NOTICE("The glowstick has already been turned on."))
return
if(on)
return
. = ..()
if(.)
user.visible_message(SPAN_NOTICE("[user] cracks and shakes the glowstick."), SPAN_NOTICE("You crack and shake the glowstick, turning it on!"))
START_PROCESSING(SSobj, src)
/obj/item/flashlight/glowstick/red
name = "red glowstick"
desc = "A red military-grade glowstick."
icon_state = "glowstick_red"
item_state = "glowstick_red"
light_color = LIGHT_COLOR_RED
/obj/item/flashlight/glowstick/blue
name = "blue glowstick"
desc = "A blue military-grade glowstick."
icon_state = "glowstick_blue"
item_state = "glowstick_blue"
light_color = LIGHT_COLOR_BLUE
/obj/item/flashlight/glowstick/orange
name = "orange glowstick"
desc = "A orange military-grade glowstick."
icon_state = "glowstick_orange"
item_state = "glowstick_orange"
light_color = LIGHT_COLOR_ORANGE
/obj/item/flashlight/glowstick/yellow
name = "yellow glowstick"
desc = "A yellow military-grade glowstick."
icon_state = "glowstick_yellow"
item_state = "glowstick_yellow"
light_color = LIGHT_COLOR_YELLOW