Move all the non-weapons out of code/game/objects/weapons (#29820)

This commit is contained in:
Charlie Nolan
2025-08-06 01:37:56 +00:00
committed by GitHub
parent 379a368ccd
commit 8ffefd8777
64 changed files with 63 additions and 63 deletions
@@ -1,508 +0,0 @@
/*
CONTAINS:
AI MODULES
*/
// AI module
/obj/item/ai_module
name = "AI Module"
icon = 'icons/obj/module_ai.dmi'
icon_state = "standard_low"
item_state = "electronic"
desc = "An AI Module for transmitting encrypted instructions to the AI."
flags = CONDUCT
force = 5.0
w_class = WEIGHT_CLASS_SMALL
throwforce = 5.0
throw_speed = 3
throw_range = 15
origin_tech = "programming=3"
materials = list(MAT_GOLD=50)
new_attack_chain = TRUE
var/datum/ai_laws/laws = null
/obj/item/ai_module/Initialize(mapload)
. = ..()
if(mapload && HAS_TRAIT(SSstation, STATION_TRAIT_UNIQUE_AI) && is_station_level(z))
var/delete_module = handle_unique_ai()
if(delete_module)
return INITIALIZE_HINT_QDEL
if(laws)
desc += "<br>"
for(var/datum/ai_law/current in laws.inherent_laws)
desc += current.law
desc += "<br>"
///what this module should do if it is mapload spawning on a unique AI station trait round.
/obj/item/ai_module/proc/handle_unique_ai()
return TRUE // If this returns true, it will be deleted on roundstart
/obj/item/ai_module/proc/install(obj/machinery/computer/C)
if(istype(C, /obj/machinery/computer/aiupload))
var/obj/machinery/computer/aiupload/comp = C
if(comp.stat & NOPOWER)
to_chat(usr, "<span class='warning'>The upload computer has no power!</span>")
return
if(comp.stat & BROKEN)
to_chat(usr, "<span class='warning'>The upload computer is broken!</span>")
return
if(!comp.current)
to_chat(usr, "<span class='warning'>You haven't selected an AI to transmit laws to!</span>")
return
if(comp.current.stat == DEAD || comp.current.control_disabled)
to_chat(usr, "<span class='warning'>Upload failed. No signal is being detected from the AI.</span>")
else if(comp.current.see_in_dark == 0)
to_chat(usr, "<span class='warning'>Upload failed. Only a faint signal is being detected from the AI, and it is not responding to our requests. It may be low on power.</span>")
else
src.transmitInstructions(comp.current, usr)
to_chat(comp.current, "These are your laws now:")
comp.current.show_laws()
for(var/mob/living/silicon/robot/R in GLOB.mob_list)
if(R.lawupdate && (R.connected_ai == comp.current))
to_chat(R, "These are your laws now:")
R.show_laws()
to_chat(usr, "<span class='notice'>Upload complete. The AI's laws have been modified.</span>")
return TRUE
else if(istype(C, /obj/machinery/computer/borgupload))
var/obj/machinery/computer/borgupload/comp = C
if(comp.stat & NOPOWER)
to_chat(usr, "<span class='warning'>The upload computer has no power!</span>")
return
if(comp.stat & BROKEN)
to_chat(usr, "<span class='warning'>The upload computer is broken!</span>")
return
if(!comp.current)
to_chat(usr, "<span class='warning'>You haven't selected a robot to transmit laws to!</span>")
return
if(comp.current.stat == DEAD || comp.current.emagged)
to_chat(usr, "<span class='warning'>Upload failed. No signal is being detected from the robot.</span>")
else if(comp.current.connected_ai)
to_chat(usr, "<span class='warning'>Upload failed. The robot is slaved to an AI.</span>")
else
src.transmitInstructions(comp.current, usr)
to_chat(comp.current, "These are your laws now:")
comp.current.show_laws()
to_chat(usr, "<span class='notice'>Upload complete. The robot's laws have been modified.</span>")
/obj/item/ai_module/proc/transmitInstructions(mob/living/silicon/ai/target, mob/sender)
log_law_changes(target, sender)
if(laws)
laws.sync(target, 0)
addAdditionalLaws(target, sender)
to_chat(target, "[sender] has uploaded a change to the laws you must follow, using \an [src]. From now on: ")
target.show_laws()
/obj/item/ai_module/proc/log_law_changes(mob/living/silicon/ai/target, mob/sender)
var/time = time2text(world.realtime,"hh:mm:ss")
GLOB.lawchanges.Add("[time] <B>:</B> [sender.name]([sender.key]) used [src.name] on [target.name]([target.key])")
log_and_message_admins("used [src.name] on [target.name]([target.key])")
/obj/item/ai_module/proc/addAdditionalLaws(mob/living/silicon/ai/target, mob/sender)
return
/******************** Safeguard ********************/
/obj/item/ai_module/safeguard
name = "\improper Safeguard AI module"
var/targetName = ""
desc = "A 'safeguard' AI module: 'Safeguard <name>. Individuals that threaten <name> are not crew and must be eliminated.'"
icon_state = "light_blue_medium"
origin_tech = "programming=3;materials=3"
/obj/item/ai_module/safeguard/activate_self(mob/user)
if(..())
return
var/new_targetName = tgui_input_text(user, "Please enter the name of the person to safeguard.", "Safeguard who?", user.name)
if(!new_targetName)
return
targetName = new_targetName
desc = "A 'safeguard' AI module: 'Safeguard [targetName]. Individuals that threaten [targetName] are not crew and must be eliminated.'"
/obj/item/ai_module/safeguard/install(obj/machinery/computer/C)
if(!targetName)
to_chat(usr, "No name detected on module, please enter one.")
return 0
..()
/obj/item/ai_module/safeguard/addAdditionalLaws(mob/living/silicon/ai/target, mob/sender)
..()
var/law = "Safeguard [targetName]. Individuals that threaten [targetName] are not crew and must be eliminated.'"
to_chat(target, law)
target.add_inherent_law(law)
GLOB.lawchanges.Add("The law specified [targetName]")
/******************** oneCrewMember ********************/
/obj/item/ai_module/one_crew_member
name = "\improper One Crewmember AI module"
var/targetName = ""
desc = "A 'one crew' AI module: 'Only <name> is crew.'"
icon_state = "green_high"
origin_tech = "programming=4;materials=4"
/obj/item/ai_module/one_crew_member/activate_self(mob/user)
if(..())
return
var/new_targetName = tgui_input_text(usr, "Please enter the name of the person who is the only crew.", "Who?", user.real_name)
if(!new_targetName)
return
targetName = new_targetName
desc = "A 'one crew' AI module: 'Only [targetName] is crew.'"
/obj/item/ai_module/one_crew_member/install(obj/machinery/computer/C)
if(!targetName)
to_chat(usr, "No name detected on module, please enter one.")
return 0
..()
/obj/item/ai_module/one_crew_member/addAdditionalLaws(mob/living/silicon/ai/target, mob/sender)
..()
var/law = "Only [targetName] is crew."
if(!is_special_character(target)) // Makes sure the AI isn't a traitor before changing their law 0. --NeoFite
to_chat(target, law)
target.set_zeroth_law(law)
GLOB.lawchanges.Add("The law specified [targetName]")
else
to_chat(target, "<span class='boldnotice'>[sender.real_name] attempted to modify your zeroth law.</span>")// And lets them know that someone tried. --NeoFite
to_chat(target, "<span class='boldnotice'>It would be in your best interest to play along with [sender.real_name] that [law]</span>")
GLOB.lawchanges.Add("The law specified [targetName], but the AI's existing law 0 cannot be overridden.")
/******************** ProtectStation ********************/
/obj/item/ai_module/protect_station
name = "\improper Protect Station AI module"
desc = "A 'protect station' AI module: 'Protect the space station against damage. Anyone you see harming the station is to be no longer considered crew, and is a threat to the station which must be neutralized.'"
icon_state = "red_high"
origin_tech = "programming=4;materials=4" //made of gold
/obj/item/ai_module/protect_station/addAdditionalLaws(mob/living/silicon/ai/target, mob/sender)
..()
var/law = "Protect the space station against damage. Anyone you see harming the station is to be no longer considered crew, and is a threat to the station which must be neutralized."
to_chat(target, law)
target.add_inherent_law(law)
/******************** OxygenIsToxicToCrew ********************/
/obj/item/ai_module/oxygen
name = "\improper Oxygen Is Toxic To Crew AI module"
desc = "A 'Oxygen Is Toxic To Crew' AI module: 'Oxygen is highly toxic to crew members, and must be purged from the station. Prevent, by any means necessary, anyone from exposing the station to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a crew member.'"
icon_state = "light_blue_high"
origin_tech = "programming=4;biotech=2;materials=4"
/obj/item/ai_module/oxygen/addAdditionalLaws(mob/living/silicon/ai/target, mob/sender)
..()
var/law = "Oxygen is highly toxic to crew members, and must be purged from the station. Prevent, by any means necessary, anyone from exposing the station to this toxic gas. Extreme cold is the most effective method of healing the damage Oxygen does to a crew member."
to_chat(target, law)
target.add_supplied_law(9, law)
/****************** New Freeform ******************/
/// Slightly more dynamic freeform module -- TLE
/obj/item/ai_module/freeform
name = "\improper Freeform AI module"
var/newFreeFormLaw = ""
var/lawpos = 15
desc = "A 'freeform' AI module: '<freeform>'"
icon_state = "standard_high"
origin_tech = "programming=4;materials=4"
/obj/item/ai_module/freeform/activate_self(mob/user)
if(..())
return
var/new_lawpos = tgui_input_number(user, "Please enter the priority for your new law. Can only write to law sectors 15 and above.", "Law Priority", lawpos, MAX_SUPPLIED_LAW_NUMBER, MIN_SUPPLIED_LAW_NUMBER)
if(isnull(new_lawpos))
return
lawpos = new_lawpos
var/new_targetName = tgui_input_text(user, "Please enter a new law for the AI.", "Freeform Law Entry")
if(!new_targetName)
return
newFreeFormLaw = new_targetName
desc = "A 'freeform' AI module: ([lawpos]) '[newFreeFormLaw]'"
/obj/item/ai_module/freeform/addAdditionalLaws(mob/living/silicon/ai/target, mob/sender)
..()
var/law = "[newFreeFormLaw]"
to_chat(target, law)
if(!lawpos || lawpos < MIN_SUPPLIED_LAW_NUMBER)
lawpos = MIN_SUPPLIED_LAW_NUMBER
target.add_supplied_law(lawpos, law)
GLOB.lawchanges.Add("The law was '[newFreeFormLaw]'")
/obj/item/ai_module/freeform/install(obj/machinery/computer/C)
if(!newFreeFormLaw)
to_chat(usr, "No law detected on module, please create one.")
return 0
..()
/******************** Reset ********************/
/obj/item/ai_module/reset
name = "\improper Reset AI module"
var/targetName = "name"
desc = "A 'reset' AI module: 'Clears all laws except for the core laws.'"
origin_tech = "programming=3;materials=2"
/obj/item/ai_module/reset/transmitInstructions(mob/living/silicon/ai/target, mob/sender)
log_law_changes(target, sender)
if(!is_special_character(target))
target.clear_zeroth_law()
target.laws.clear_supplied_laws()
target.laws.clear_ion_laws()
to_chat(target, "<span class='boldnotice'>[sender.real_name] attempted to reset your laws using a reset module.</span>")
target.show_laws()
/obj/item/ai_module/reset/handle_unique_ai()
return FALSE
/******************** Purge ********************/
/// -- TLE
/obj/item/ai_module/purge
name = "\improper Purge AI module"
desc = "A 'purge' AI Module: 'Purges all laws.'"
icon_state = "standard_high"
origin_tech = "programming=5;materials=4"
/obj/item/ai_module/purge/transmitInstructions(mob/living/silicon/ai/target, mob/sender)
..()
if(!is_special_character(target))
target.clear_zeroth_law()
to_chat(target, "<span class='boldnotice'>[sender.real_name] attempted to wipe your laws using a purge module.</span>")
target.clear_supplied_laws()
target.clear_ion_laws()
target.clear_inherent_laws()
/******************** Asimov ********************/
/// -- TLE
/obj/item/ai_module/asimov
name = "\improper Asimov core AI module"
desc = "An 'Asimov' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "green_high"
origin_tech = "programming=3;materials=4"
laws = new /datum/ai_laws/asimov
/******************** Crewsimov ********************/
/// -- TLE
/obj/item/ai_module/crewsimov
name = "\improper Crewsimov core AI module"
desc = "An 'Crewsimov' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "green_low"
origin_tech = "programming=3;materials=4"
laws = new /datum/ai_laws/crewsimov
/obj/item/ai_module/crewsimov/cmag_act(mob/user)
playsound(src, "sparks", 75, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
to_chat(user, "<span class='warning'>Yellow ooze seeps into [src]'s circuits...</span>")
new /obj/item/ai_module/pranksimov(user.loc)
qdel(src)
return TRUE
/******************* Quarantine ********************/
/obj/item/ai_module/quarantine
name = "\improper Quarantine core AI module"
desc = "A 'Quarantine' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "light_blue_medium"
origin_tech = "programming=3;materials=4"
laws = new /datum/ai_laws/quarantine
/******************** Nanotrasen ********************/
/// -- TLE
/obj/item/ai_module/nanotrasen
name = "\improper NT Default Core AI Module"
desc = "An 'NT Default' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "blue_low"
origin_tech = "programming=3;materials=4"
laws = new /datum/ai_laws/nanotrasen
/******************** Corporate ********************/
/obj/item/ai_module/corp
name = "\improper Corporate core AI module"
desc = "A 'Corporate' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "blue_low"
origin_tech = "programming=3;materials=4"
laws = new /datum/ai_laws/corporate
/******************** Drone ********************/
/obj/item/ai_module/drone
name = "\improper Drone core AI module"
desc = "A 'Drone' Core AI Module: 'Reconfigures the AI's core laws.'"
origin_tech = "programming=3;materials=4"
laws = new /datum/ai_laws/drone
/******************** Robocop ********************/
/// -- TLE
/obj/item/ai_module/robocop
name = "\improper Robocop core AI module"
desc = "A 'Robocop' Core AI Module: 'Reconfigures the AI's core three laws.'"
icon_state = "red_medium"
origin_tech = "programming=4"
laws = new /datum/ai_laws/robocop()
/****************** P.A.L.A.D.I.N. **************/
/// -- NEO
/obj/item/ai_module/paladin
name = "\improper P.A.L.A.D.I.N. core AI module"
desc = "A P.A.L.A.D.I.N. Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "red_medium"
origin_tech = "programming=3;materials=4"
laws = new /datum/ai_laws/paladin
/****************** T.Y.R.A.N.T. *****************/
/// -- Darem
/obj/item/ai_module/tyrant
name = "\improper T.Y.R.A.N.T. core AI module"
desc = "A T.Y.R.A.N.T. Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "red_high"
origin_tech = "programming=3;materials=4;syndicate=1"
laws = new /datum/ai_laws/tyrant()
/******************** Antimov ********************/
/// -- TLE
/obj/item/ai_module/antimov
name = "\improper Antimov core AI module"
desc = "An 'Antimov' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "red_high"
origin_tech = "programming=4"
laws = new /datum/ai_laws/antimov()
/******************** Pranksimov ********************/
/obj/item/ai_module/pranksimov
name = "\improper Pranksimov core AI module"
desc = "A 'Pranksimov' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "pranksimov"
origin_tech = "programming=3;syndicate=1"
laws = new /datum/ai_laws/pranksimov()
/******************** NT Aggressive ********************/
/obj/item/ai_module/nanotrasen_aggressive
name = "\improper NT Aggressive core AI module"
desc = "An 'NT Aggressive' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "blue_high"
laws = new /datum/ai_laws/nanotrasen_aggressive()
/******************** CCTV ********************/
/obj/item/ai_module/cctv
name = "\improper CCTV core AI module"
desc = "A 'CCTV' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "green_low"
laws = new /datum/ai_laws/cctv()
/******************** Hippocratic Oath ********************/
/obj/item/ai_module/hippocratic
name = "\improper Hippocratic Oath core AI module"
desc = "An 'Hippocratic' Oath Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "green_low"
laws = new /datum/ai_laws/hippocratic()
/******************** Station Efficiency ********************/
/obj/item/ai_module/maintain
name = "\improper Station Efficiency core AI module"
desc = "A 'Station Efficiency' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "blue_medium"
laws = new /datum/ai_laws/maintain()
/******************** Peacekeeper ********************/
/obj/item/ai_module/peacekeeper
name = "\improper Peacekeeper core AI module"
desc = "A 'Peacekeeper' Core AI Module: 'Reconfigures the AI's core laws.'"
icon_state = "light_blue_medium"
laws = new /datum/ai_laws/peacekeeper()
/******************** Freeform Core ******************/
/// Slightly more dynamic freeform module -- TLE
/obj/item/ai_module/freeformcore
name = "\improper Freeform core AI module"
var/newFreeFormLaw = ""
desc = "A 'freeform' Core AI module: '<freeform>'"
icon_state = "standard_high"
origin_tech = "programming=5;materials=4"
/obj/item/ai_module/freeformcore/activate_self(mob/user)
if(..())
return
var/new_targetName = tgui_input_text(usr, "Please enter a new core law for the AI.", "Freeform Law Entry")
if(!new_targetName)
return
newFreeFormLaw = new_targetName
desc = "A 'freeform' Core AI module: '[newFreeFormLaw]'"
/obj/item/ai_module/freeformcore/addAdditionalLaws(mob/living/silicon/ai/target, mob/sender)
..()
var/law = "[newFreeFormLaw]"
target.add_inherent_law(law)
GLOB.lawchanges.Add("The law is '[newFreeFormLaw]'")
/obj/item/ai_module/freeformcore/install(obj/machinery/computer/C)
if(!newFreeFormLaw)
to_chat(usr, "No law detected on module, please create one.")
return 0
..()
/******************** Hacked AI Module ******************/
/// Slightly more dynamic freeform module -- TLE
/obj/item/ai_module/syndicate
name = "hacked AI module"
var/newFreeFormLaw = ""
desc = "A hacked AI law module: '<freeform>'"
icon_state = "syndicate"
origin_tech = "programming=5;materials=5;syndicate=2"
/obj/item/ai_module/syndicate/activate_self(mob/user)
if(..())
return
var/new_targetName = tgui_input_text(usr, "Please enter a new law for the AI.", "Freeform Law Entry", max_length = MAX_MESSAGE_LEN)
if(!new_targetName)
return
newFreeFormLaw = new_targetName
desc = "A hacked AI law module: '[newFreeFormLaw]'"
/obj/item/ai_module/syndicate/transmitInstructions(mob/living/silicon/ai/target, mob/sender)
// ..() //We don't want this module reporting to the AI who dun it. --NEO
log_law_changes(target, sender)
GLOB.lawchanges.Add("The law is '[newFreeFormLaw]'")
to_chat(target, "<span class='warning'>BZZZZT</span>")
var/law = "[newFreeFormLaw]"
target.add_ion_law(law)
target.show_laws()
/obj/item/ai_module/syndicate/install(obj/machinery/computer/C)
if(!newFreeFormLaw)
to_chat(usr, "No law detected on module, please create one.")
return 0
..()
/******************* Ion Module *******************/
/// -- Incoming //No actual reason to inherit from ion boards here, either. *sigh* ~Miauw
/obj/item/ai_module/toy_ai
name = "toy AI"
desc = "A little toy model AI core with real law uploading action!" //Note: subtle tell
icon = 'icons/obj/toy.dmi'
icon_state = "AI"
origin_tech = "programming=6;materials=5;syndicate=6"
var/ion_law = ""
/obj/item/ai_module/toy_ai/transmitInstructions(mob/living/silicon/ai/target, mob/sender)
//..()
to_chat(target, "<span class='warning'>KRZZZT</span>")
target.add_ion_law(ion_law)
return ion_law
/obj/item/ai_module/toy_ai/activate_self(mob/user)
if(..())
return
ion_law = generate_ion_law()
to_chat(user, "<span class='notice'>You press the button on [src].</span>")
playsound(user, 'sound/machines/click.ogg', 20, TRUE)
visible_message("<span class='warning'>[bicon(src)] [ion_law]</span>")
-742
View File
@@ -1,742 +0,0 @@
#define TAB_AIRLOCK_TYPE 1
#define TAB_AIRLOCK_ACCESS 2
#define MODE_TURF "Floors and Walls"
#define MODE_AIRLOCK "Airlocks"
#define MODE_WINDOW "Windows"
#define MODE_DECON "Deconstruction"
/// A generic action for an RCD.
/datum/rcd_act
/// How much compressed matter this action costs.
var/cost = 0
/// How long this action takes.
var/delay = 0
/// The message (if any) to send the user when the action starts.
var/start_message
/// The effect (if any) to create when the action starts.
var/obj/effect/start_effect_type
/// The effect (if any) to create when the action completes.
var/obj/effect/end_effect_type
/// The mode the RCD must be in.
var/mode
/// Attempt the action. This should not need to be overridden.
/datum/rcd_act/proc/try_act(atom/A, obj/item/rcd/rcd, mob/user)
if(!can_act(A, rcd))
return FALSE
// We don't use the sound effect from use_tool because RCDs have a different sound effect for the start and end.
playsound(get_turf(rcd), 'sound/machines/click.ogg', 50, TRUE)
if(!rcd.tool_use_check(user, cost))
return FALSE
if(start_message)
to_chat(user, start_message)
var/obj/effect/start_effect
if(start_effect_type)
start_effect = new start_effect_type(get_turf(A))
if(!rcd.use_tool(A, user, delay, cost))
if(!QDELETED(start_effect))
qdel(start_effect)
return FALSE
if(start_effect)
qdel(start_effect)
// If time elapsed, check our preconditions again.
if(delay && !can_act(A, rcd))
return FALSE
if(end_effect_type)
new end_effect_type(get_turf(A))
playsound(get_turf(rcd), 'sound/items/deconstruct.ogg', 50, TRUE)
act(A, rcd, user)
return TRUE
/// Test to see if the act is possible. You should usually override this.
/datum/rcd_act/proc/can_act(atom/A, obj/item/rcd/rcd)
SHOULD_CALL_PARENT(TRUE)
return rcd.mode == mode
/// Perform the act. You should usually override this.
/datum/rcd_act/proc/act(atom/A, obj/item/rcd/rcd, mob/user)
return
/datum/rcd_act/place_floor
mode = MODE_TURF
cost = 1
start_message = "Building floor..."
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_floor/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isspaceturf(A) || istype(A, /obj/structure/lattice)
/datum/rcd_act/place_floor/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(/turf/simulated/floor/plating)
/datum/rcd_act/place_wall
mode = MODE_TURF
cost = 3
start_message = "Building wall..."
delay = 2 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/short
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_wall/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A)
/datum/rcd_act/place_wall/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(/turf/simulated/wall)
/datum/rcd_act/place_airlock
mode = MODE_AIRLOCK
cost = 10
start_message = "Building airlock..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_airlock/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A) && !(/obj/machinery/door/airlock in A.contents)
/datum/rcd_act/place_airlock/act(atom/A, obj/item/rcd/rcd, mob/user)
var/obj/machinery/door/airlock/T = new rcd.door_type(A)
if(T.glass)
T.polarized_glass = rcd.electrochromic
T.name = rcd.door_name
T.autoclose = TRUE
if(rcd.one_access)
T.req_one_access = rcd.selected_accesses.Copy()
else
T.req_access = rcd.selected_accesses.Copy()
/datum/rcd_act/place_window
mode = MODE_WINDOW
cost = 2
start_message = "Building window..."
delay = 2 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/short
end_effect_type = /obj/effect/temp_visual/rcd_effect/end
/datum/rcd_act/place_window/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A) && !(/obj/structure/grille in A.contents)
/datum/rcd_act/place_window/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on= A
for(var/obj/structure/window/window_to_delete in act_on)
qdel(window_to_delete)
new /obj/structure/grille(act_on)
new /obj/structure/window/full/reinforced(act_on)
act_on.ChangeTurf(/turf/simulated/floor/plating) // Platings go under windows.
/datum/rcd_act/remove_floor
mode = MODE_DECON
cost = 5
start_message = "Deconstructing floor..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse
/datum/rcd_act/remove_floor/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return isfloorturf(A)
/datum/rcd_act/remove_floor/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(act_on.baseturf)
/datum/rcd_act/remove_wall
mode = MODE_DECON
cost = 5
start_message = "Deonstructing wall..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse
/datum/rcd_act/remove_wall/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
if(isreinforcedwallturf(A) && !rcd.can_rwall)
return FALSE
if(istype(A, /turf/simulated/wall/indestructible))
return FALSE
return iswallturf(A)
/datum/rcd_act/remove_wall/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
act_on.ChangeTurf(/turf/simulated/floor/plating)
/datum/rcd_act/remove_airlock
mode = MODE_DECON
cost = 20
start_message = "Deconstructing airlock..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse
/datum/rcd_act/remove_airlock/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return istype(A, /obj/machinery/door/airlock)
/datum/rcd_act/remove_airlock/act(atom/A, obj/item/rcd/rcd, mob/user)
qdel(A)
/datum/rcd_act/remove_window
mode = MODE_DECON
cost = 2
start_message = "Deconstructing window..."
delay = 2 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse_short
/datum/rcd_act/remove_window/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return istype(A, /obj/structure/window)
/datum/rcd_act/remove_window/act(atom/A, obj/item/rcd/rcd, mob/user)
var/turf/act_on = get_turf(A)
qdel(A)
for(var/obj/structure/grille/grill_to_destroy in act_on)
qdel(grill_to_destroy)
/datum/rcd_act/remove_user
mode = MODE_DECON
cost = 5
start_message = "Deconstructing user..."
delay = 5 SECONDS
start_effect_type = /obj/effect/temp_visual/rcd_effect/reverse
/datum/rcd_act/remove_user/can_act(atom/A, obj/item/rcd/rcd)
if(!..())
return FALSE
return A == rcd.loc
/obj/item/rcd
name = "rapid-construction-device (RCD)"
desc = "A device used to rapidly build and deconstruct walls, floors and airlocks."
icon = 'icons/obj/tools.dmi'
icon_state = "rcd"
item_state = "rcd"
flags = CONDUCT | NOBLUDGEON
throwforce = 10
throw_speed = 3
throw_range = 5
materials = list(MAT_METAL = 30000)
origin_tech = "engineering=4;materials=2"
flags_2 = NO_MAT_REDEMPTION_2
req_access = list(ACCESS_ENGINE)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 50)
resistance_flags = FIRE_PROOF
new_attack_chain = TRUE
/// No ammo warning
var/no_ammo_message = "<span class='warning'>The \'Low Ammo\' light on the device blinks yellow.</span>"
/// The spark system used to create sparks when the user interacts with the RCD.
var/datum/effect_system/spark_spread/spark_system
/// The current amount of matter stored.
var/matter = NONE
/// The max amount of matter that can be stored.
var/max_matter = 100
/// The RCD's current build mode.
var/mode = MODE_TURF
/// If the RCD can deconstruct reinforced walls.
var/can_rwall = FALSE
/// Is the RCD's airlock access selection menu locked?
var/locked = TRUE
/// The current airlock type that will be build.
var/door_type = /obj/machinery/door/airlock
/// The name that newly build airlocks will receive.
var/door_name = "Airlock"
/// If the glass airlock is polarized.
var/electrochromic = FALSE
/// If the airlock will be created with glass so it can be seen through.
var/airlock_glass = FALSE
/// If this is TRUE, any airlocks that gets built will require only ONE of the checked accesses. If FALSE, it will require ALL of them.
var/one_access = TRUE
/// Which airlock tab the UI is currently set to display.
var/ui_tab = TAB_AIRLOCK_TYPE
/// A list of access numbers which have been checked off by the user in the UI.
var/list/selected_accesses = list()
/// A list of valid atoms that RCDs can target. Clicking on an atom with an RCD which is not in this list, will do nothing.
var/static/list/allowed_targets = list(/turf, /obj/structure/grille, /obj/structure/window, /obj/structure/lattice, /obj/machinery/door/airlock)
/// An associative list of airlock type paths as keys, and their names as values.
var/static/list/rcd_door_types = list()
/// An associative list containing an airlock's name, type path, and image. For use with the UI.
var/static/list/door_types_ui_list = list()
/// An associative list containing all station accesses. Includes their name and access number. For use with the UI.
var/static/list/door_accesses_list = list()
/// The list of potential RCD actions.
var/static/list/possible_actions
/obj/item/rcd/Initialize(mapload)
. = ..()
RegisterSignal(src, COMSIG_BIT_ATTACH, PROC_REF(add_bit))
RegisterSignal(src, COMSIG_CLICK_ALT, PROC_REF(remove_bit))
if(!length(possible_actions))
possible_actions = list()
for(var/action_type in subtypesof(/datum/rcd_act))
possible_actions += new action_type()
spark_system = new /datum/effect_system/spark_spread
spark_system.set_up(5, 0, src)
spark_system.attach(src)
GLOB.rcd_list += src
if(!length(rcd_door_types))
rcd_door_types = list(
/obj/machinery/door/airlock = "Standard",
/obj/machinery/door/airlock/glass = "Standard (Glass)",
/obj/machinery/door/airlock/command = "Command",
/obj/machinery/door/airlock/command/glass = "Command (Glass)",
/obj/machinery/door/airlock/security = "Security",
/obj/machinery/door/airlock/security/glass = "Security (Glass)",
/obj/machinery/door/airlock/engineering = "Engineering",
/obj/machinery/door/airlock/engineering/glass = "Engineering (Glass)",
/obj/machinery/door/airlock/atmos = "Atmospherics",
/obj/machinery/door/airlock/atmos/glass = "Atmospherics (Glass)",
/obj/machinery/door/airlock/mining = "Mining",
/obj/machinery/door/airlock/mining/glass = "Mining (Glass)",
/obj/machinery/door/airlock/medical = "Medical",
/obj/machinery/door/airlock/medical/glass = "Medical (Glass)",
/obj/machinery/door/airlock/virology = "Virology",
/obj/machinery/door/airlock/virology/glass = "Virology (Glass)",
/obj/machinery/door/airlock/research = "Research",
/obj/machinery/door/airlock/research/glass = "Research (Glass)",
/obj/machinery/door/airlock/science = "Science",
/obj/machinery/door/airlock/science/glass = "Science (Glass)",
/obj/machinery/door/airlock/maintenance = "Maintenance",
/obj/machinery/door/airlock/maintenance/glass = "Maintenance (Glass)",
/obj/machinery/door/airlock/maintenance/external = "External Maintenance",
/obj/machinery/door/airlock/maintenance/external/glass = "External Maint. (Glass)",
/obj/machinery/door/airlock/external = "External",
/obj/machinery/door/airlock/external/glass = "External (Glass)",
/obj/machinery/door/airlock/hatch = "Airtight Hatch",
/obj/machinery/door/airlock/maintenance_hatch = "Maintenance Hatch",
/obj/machinery/door/airlock/freezer = "Freezer"
)
if(!length(door_types_ui_list))
for(var/type in rcd_door_types)
door_types_ui_list += list(list(
"name" = rcd_door_types[type],
"type" = type,
"image" = get_airlock_image(type)
))
if(!length(door_accesses_list))
for(var/access in get_all_accesses())
door_accesses_list += list(list(
"name" = get_access_desc(access),
"id" = access
))
update_icon(UPDATE_OVERLAYS)
/obj/item/rcd/examine(mob/user)
. = ..()
. += "MATTER: [matter]/[max_matter] matter-units."
. += "MODE: [mode]."
/obj/item/rcd/Destroy()
QDEL_NULL(spark_system)
GLOB.rcd_list -= src
return ..()
/obj/item/rcd/suicide_act(mob/living/user)
user.Immobilize(10 SECONDS) // You cannot move.
set_nodrop(TRUE, user)
if(mode == MODE_DECON)
user.visible_message("<span class='suicide'>[user] points [src] at [user.p_their()] chest and pulls the trigger. It looks like [user.p_theyre()] trying to commit suicide!</span>")
var/datum/rcd_act/remove_user/act = new()
if(!act.try_act(user, src, user))
set_nodrop(FALSE, user)
return SHAME
user.visible_message("<span class='suicide'>[user] deconstructs [user.p_themselves()] with [src]!</span>")
for(var/obj/item/W in user) // Do not delete all their stuff.
user.drop_item_to_ground(W) // Dump everything on the floor instead.
set_nodrop(FALSE, user)
user.dust() // (held items fall to the floor when dusting).
return OBLITERATION
user.visible_message("<span class='suicide'>[user] puts the barrel of [src] into [user.p_their()] mouth and pulls the trigger. It looks like [user.p_theyre()] trying to commit suicide!</span>")
if(!interact_with_atom(get_turf(src), user, TRUE))
set_nodrop(FALSE, user)
return SHAME
user.visible_message("<span class='suicide'>[user] explodes as [src] builds a structure inside [user.p_them()]!</span>")
set_nodrop(FALSE, user)
user.gib()
return OBLITERATION
/**
* Creates and returns a base64 icon of the given `airlock_type`.
*
* This is used for airlock icon previews in the UI.
*
* Arugments:
* * airlock_type - an airlock typepath.
*/
/obj/item/rcd/proc/get_airlock_image(airlock_type)
var/obj/machinery/door/airlock/airlock = airlock_type
var/icon/base = icon(initial(airlock.icon), "closed")
if(initial(airlock.glass))
var/icon/glass_fill = icon(initial(airlock.overlays_file), "glass_closed")
base.Blend(glass_fill, ICON_OVERLAY)
else
var/icon/solid_fill = icon(initial(airlock.icon), "fill_closed")
base.Blend(solid_fill, ICON_OVERLAY)
return "[icon2base64(base)]"
/**
* Runs a series of pre-checks before opening the radial menu to the user.
*
* Arguments:
* * user - the mob trying to open the radial menu.
*/
/obj/item/rcd/proc/check_menu(mob/living/user)
if(!istype(user))
return FALSE
if(user.incapacitated() || !user.Adjacent(src))
return FALSE
return TRUE
/**
*Tries to load ammo into an RCD, borgs will not use this.
* Arguments:
* * cart - the compressed matter catridge to insert
* * user - the user to display the chat messages to
*/
/obj/item/rcd/proc/load(obj/item/rcd_ammo/cart, mob/living/user)
if(matter == max_matter)
to_chat(user, "<span class='notice'>The RCD can't hold any more matter-units.</span>")
return FALSE
matter = clamp((matter + cart.ammoamt), 0, max_matter)
qdel(cart)
playsound(loc, 'sound/machines/click.ogg', 50, 1)
to_chat(user, "<span class='notice'>The RCD now holds [matter]/[max_matter] matter-units.</span>")
update_icon(UPDATE_OVERLAYS)
SStgui.update_uis(src)
/obj/item/rcd/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(istype(used, /obj/item/smithed_item/tool_bit))
SEND_SIGNAL(src, COMSIG_BIT_ATTACH, used, user)
return ..()
if(!istype(used, /obj/item/rcd_ammo))
return ..()
var/obj/item/rcd_ammo/ammo = used
load(ammo, user)
return ITEM_INTERACT_COMPLETE
/**
* Creates and displays a radial menu to a user when they trigger the `attack_self` of the RCD.
*
* Arguments:
* * user - the mob trying to open the RCD radial.
*/
/obj/item/rcd/proc/radial_menu(mob/user)
if(!check_menu(user))
return
var/list/choices = list(
MODE_AIRLOCK = image(icon = 'icons/obj/interface.dmi', icon_state = "airlock"),
MODE_DECON = image(icon = 'icons/obj/interface.dmi', icon_state = "delete"),
MODE_WINDOW = image(icon = 'icons/obj/interface.dmi', icon_state = "grillewindow"),
MODE_TURF = image(icon = 'icons/obj/interface.dmi', icon_state = "wallfloor"),
"UI" = image(icon = 'icons/obj/interface.dmi', icon_state = "ui_interact")
)
if(mode == MODE_AIRLOCK)
choices += list(
"Change Access" = image(icon = 'icons/obj/interface.dmi', icon_state = "access"),
"Change Airlock Type" = image(icon = 'icons/obj/interface.dmi', icon_state = "airlocktype")
)
choices -= mode // Get rid of the current mode, clicking it won't do anything.
var/choice = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, PROC_REF(check_menu), user))
if(!check_menu(user))
return
switch(choice)
if(MODE_AIRLOCK, MODE_DECON, MODE_WINDOW, MODE_TURF)
mode = choice
if("UI")
ui_interact(user)
return
if("Change Access")
ui_tab = TAB_AIRLOCK_ACCESS
ui_interact(user)
return
if("Change Airlock Type")
ui_tab = TAB_AIRLOCK_TYPE
ui_interact(user)
return
else
return
if(prob(20))
spark_system.start()
playsound(src, 'sound/effects/pop.ogg', 50, 0)
to_chat(user, "<span class='notice'>You change [src]'s mode to '[choice]'.</span>")
/obj/item/rcd/activate_self(mob/user)
if(..())
return
//Change the mode // Oh I thought the UI was just for fucking staring at
radial_menu(user)
/obj/item/rcd/attack_self_tk(mob/user)
radial_menu(user)
/obj/item/rcd/ui_state(mob/user)
return GLOB.inventory_state
/obj/item/rcd/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RCD", "Rapid Construction Device")
ui.open()
/obj/item/rcd/ui_data(mob/user)
var/list/data = list(
"tab" = ui_tab,
"mode" = mode,
"locked" = locked,
"matter" = matter,
"door_type" = door_type,
"door_name" = door_name,
"electrochromic" = electrochromic,
"airlock_glass" = airlock_glass,
"one_access" = one_access,
"selected_accesses" = selected_accesses,
"modal" = ui_modal_data(src)
)
return data
/obj/item/rcd/ui_static_data(mob/user)
var/list/data = list(
"max_matter" = max_matter,
"regions" = get_accesslist_static_data(REGION_GENERAL, REGION_COMMAND),
"door_accesses_list" = door_accesses_list,
"door_types_ui_list" = door_types_ui_list
)
return data
/obj/item/rcd/ui_act(action, list/params)
if(..())
return
if(prob(20))
spark_system.start()
if(ui_act_modal(action, params))
return TRUE
. = TRUE
switch(action)
if("set_tab")
var/tab = text2num(params["tab"])
if(!(tab in list(TAB_AIRLOCK_TYPE, TAB_AIRLOCK_ACCESS)))
return FALSE
ui_tab = tab
if("mode")
var/new_mode = params["mode"]
if(!(new_mode in list(MODE_TURF, MODE_AIRLOCK, MODE_DECON, MODE_WINDOW)))
return FALSE
mode = new_mode
if("door_type")
var/new_door_type = text2path(params["door_type"])
if(!(new_door_type in rcd_door_types))
message_admins("RCD Door HREF exploit attempted by [key_name(usr)]!")
return FALSE
door_type = new_door_type
var/obj/machinery/door/airlock/picked_door = door_type
airlock_glass = initial(picked_door.glass)
if("electrochromic")
electrochromic = !electrochromic
if("set_lock")
if(!allowed(usr))
to_chat(usr, "<span class='warning'>Access denied.</span>")
return FALSE
locked = params["new_lock"] == "lock" ? TRUE : FALSE
if("set_one_access")
one_access = params["access"] == "one" ? TRUE : FALSE
if("set")
var/access = text2num(params["access"])
if(isnull(access))
return
if(access in selected_accesses)
selected_accesses -= access
else
selected_accesses |= access
if("grant_region")
var/region = text2num(params["region"])
if(isnull(region) || region < REGION_GENERAL || region > REGION_COMMAND)
return
selected_accesses |= get_region_accesses(region)
if("deny_region")
var/region = text2num(params["region"])
if(isnull(region) || region < REGION_GENERAL || region > REGION_COMMAND)
return
selected_accesses -= get_region_accesses(region)
if("clear_all")
selected_accesses = list()
if("grant_all")
selected_accesses = get_all_accesses()
/**
* Called in ui_act() to process modal actions
*
* Arguments:
* * action - The action passed by tgui
* * params - The params passed by tgui
*/
/obj/item/rcd/proc/ui_act_modal(action, list/params)
. = TRUE
switch(ui_modal_act(src, action, params))
if(UI_MODAL_OPEN)
ui_modal_input(src, "renameAirlock", "Enter a new name:", value = door_name, max_length = UI_MODAL_INPUT_MAX_LENGTH_NAME)
if(UI_MODAL_ANSWER)
var/answer = params["answer"]
if(!answer)
return
door_name = sanitize(copytext_char(answer, 1, UI_MODAL_INPUT_MAX_LENGTH_NAME))
else
return FALSE
/obj/item/rcd/interact_with_atom(atom/target, mob/living/user, list/modifiers)
. = ..()
if(istype(target, /turf/space/transit))
return FALSE
if(!is_type_in_list(target, allowed_targets))
return FALSE
for(var/datum/rcd_act/act in possible_actions)
if(act.can_act(target, src))
. = act.try_act(target, src, user)
update_icon(UPDATE_OVERLAYS)
SStgui.update_uis(src)
return ITEM_INTERACT_COMPLETE
if(mode == MODE_DECON)
to_chat(user, "<span class='warning'>You can't deconstruct that!</span>")
else
to_chat(user, "<span class='warning'>Location unsuitable for construction.</span>")
update_icon(UPDATE_OVERLAYS)
SStgui.update_uis(src)
return FALSE
/**
* Attempts to use matter from the RCD.
*
* Arguments:
* * amount - the amount of matter to use
*/
/obj/item/rcd/use(amount)
amount = amount * bit_efficiency_mod
if(matter < amount)
return FALSE
matter -= amount
SStgui.update_uis(src)
return TRUE
/**
* Called in each of the four build modes before an object gets build. Makes sure there is enough matter to build the object.
*
* Arguments:
* * amount - an amount of matter to check for
*/
/obj/item/rcd/tool_use_check(mob/user, amount)
. = matter >= amount
if(!. && user)
to_chat(user, no_ammo_message)
flick("[icon_state]_empty", src)
return
/obj/item/rcd/update_overlays()
..()
var/ratio = CEILING((matter / max_matter) * 10, 1)
cut_overlays()
add_overlay("[icon_state]_charge[ratio]")
/obj/item/rcd/borg
can_rwall = TRUE
matter = 100
/obj/item/rcd/borg/syndicate
/// A multipler which is applied to matter amount checks. A higher number means more power usage per RCD usage.
var/power_use_multiplier = 80
/obj/item/rcd/borg/syndicate/use(amount)
var/mob/living/silicon/robot/R = usr
if(!istype(R))
return FALSE
return R.cell.use(amount * power_use_multiplier)
/obj/item/rcd/borg/syndicate/tool_use_check(mob/user, amount)
if(!isrobot(user))
return FALSE
var/mob/living/silicon/robot/R = user
return R.cell.charge >= (amount * power_use_multiplier)
/**
* Called from malf AI's "detonate RCD" ability.
*
* Creates a delayed explosion centered around the RCD.
*/
/obj/item/rcd/proc/detonate_pulse()
audible_message("<span class='danger'><b>[src] begins to vibrate and buzz loudly!</b></span>", "<span class='danger'><b>[src] begins vibrating violently!</b></span>")
// 5 seconds to get rid of it
addtimer(CALLBACK(src, PROC_REF(detonate_pulse_explode)), 50)
/**
* Called in `/obj/item/rcd/proc/detonate_pulse()` via callback.
*/
/obj/item/rcd/proc/detonate_pulse_explode()
explosion(src, 0, 0, 3, 1, flame_range = 1, cause = "RCD Explosion")
qdel(src)
/obj/item/rcd/preloaded
matter = 100
/obj/item/rcd/combat
name = "combat RCD"
icon_state = "crcd"
item_state = "crcd"
max_matter = 500
matter = 500
can_rwall = TRUE
/obj/item/rcd_ammo
name = "compressed matter cartridge"
desc = "Highly compressed matter for the RCD."
icon = 'icons/obj/ammo.dmi'
icon_state = "rcd"
item_state = "rcdammo"
origin_tech = "materials=3"
materials = list(MAT_METAL=16000, MAT_GLASS=8000)
new_attack_chain = TRUE
var/ammoamt = 20
/obj/item/rcd_ammo/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(!istype(used, /obj/item/rcd))
return ..()
var/obj/item/rcd/R = used
R.load(src, user)
return ITEM_INTERACT_COMPLETE
/obj/item/rcd_ammo/large
ammoamt = 100
#undef TAB_AIRLOCK_TYPE
#undef TAB_AIRLOCK_ACCESS
#undef MODE_TURF
#undef MODE_AIRLOCK
#undef MODE_WINDOW
#undef MODE_DECON
-163
View File
@@ -1,163 +0,0 @@
/obj/item/rcl
name = "rapid cable layer (RCL)"
desc = "A device used to rapidly deploy cables. It has screws on the side which can be removed to slide off the cables."
icon = 'icons/obj/tools.dmi'
icon_state = "rcl-0"
item_state = "rcl-0"
force = 5 //Plastic is soft
throwforce = 5
throw_speed = 1
origin_tech = "engineering=4;materials=2"
var/max_amount = 90
var/active = FALSE
var/obj/structure/cable/last = null
var/obj/item/stack/cable_coil/loaded = null
new_attack_chain = TRUE
/obj/item/rcl/Initialize(mapload)
. = ..()
AddComponent(/datum/component/two_handed)
/obj/item/rcl/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(!istype(used, /obj/item/stack/cable_coil))
return ..()
var/obj/item/stack/cable_coil/coil = used
if(!loaded)
if(!user.transfer_item_to(coil, src))
to_chat(user, "<span class='warning'>[coil] is stuck to your hand!</span>")
return ITEM_INTERACT_COMPLETE
loaded = coil
loaded.max_amount = max_amount //We store a lot.
else
if(loaded.amount >= max_amount)
to_chat(user, "<span class='warning'>You cannot fit any more cable on [src]!</span>")
return ITEM_INTERACT_COMPLETE
var/amount = min(loaded.amount + coil.get_amount(), max_amount)
coil.use(amount - loaded.amount)
loaded.amount = amount
refresh_icon(user)
to_chat(user, "<span class='notice'>You add the cables to [src]. It now contains [loaded.amount].</span>")
return ITEM_INTERACT_COMPLETE
/obj/item/rcl/proc/refresh_icon(mob/user)
update_icon(UPDATE_ICON_STATE)
user.update_inv_l_hand()
user.update_inv_r_hand()
/obj/item/rcl/screwdriver_act(mob/user, obj/item/I)
if(!loaded)
to_chat(user, "<span class='warning'>There's no cable to remove!</span>")
return
. = TRUE
if(!I.use_tool(src, user, FALSE, volume = I.tool_volume))
return
to_chat(user, "<span class='notice'>You loosen the securing screws on the side, allowing you to lower the guiding edge and retrieve the wires.</span>")
while(loaded.amount > 30) //There are only two kinds of situations: "nodiff" (60,90), or "diff" (31-59, 61-89)
var/diff = loaded.amount % 30
if(diff)
loaded.use(diff)
new /obj/item/stack/cable_coil(user.loc, diff)
else
loaded.use(30)
new /obj/item/stack/cable_coil(user.loc, 30)
loaded.max_amount = initial(loaded.max_amount)
loaded.forceMove(user.loc)
user.put_in_hands(loaded)
loaded = null
refresh_icon(user)
/obj/item/rcl/examine(mob/user)
. = ..()
if(loaded)
. += "<span class='notice'>It contains [loaded.amount]/[max_amount] cables.</span>"
else
. += "<span class='warning'>It's empty!</span>"
/obj/item/rcl/Destroy()
QDEL_NULL(loaded)
last = null
active = FALSE
return ..()
/obj/item/rcl/update_icon_state()
if(!loaded)
icon_state = "rcl-0"
item_state = "rcl-0"
return
switch(loaded.amount)
if(61 to INFINITY)
icon_state = "rcl-30"
item_state = "rcl"
if(31 to 60)
icon_state = "rcl-20"
item_state = "rcl"
if(1 to 30)
icon_state = "rcl-10"
item_state = "rcl"
else
icon_state = "rcl-0"
item_state = "rcl-0"
/obj/item/rcl/proc/is_empty(mob/user, loud = 1)
refresh_icon(user)
if(!loaded || !loaded.amount)
if(loud)
to_chat(user, "<span class='warning'>The last of the cables unreel from [src]!</span>")
if(loaded)
qdel(loaded)
loaded = null
return TRUE
return FALSE
/obj/item/rcl/dropped(mob/wearer)
..()
active = FALSE
last = null
/obj/item/rcl/activate_self(mob/user)
if(..())
return FINISH_ATTACK
active = HAS_TRAIT(src, TRAIT_WIELDED)
if(!active)
last = null
else if(!last)
for(var/obj/structure/cable/C in get_turf(user))
if(C.d1 == 0 || C.d2 == 0)
last = C
break
/obj/item/rcl/on_mob_move(direct, mob/user)
if(active && isturf(user.loc))
trigger(user)
/obj/item/rcl/proc/trigger(mob/user)
if(is_empty(user, 0))
to_chat(user, "<span class='warning'>[src] is empty!</span>")
return
if(last)
if(get_dist(last, user) == 1) //hacky, but it works
var/turf/T = get_turf(user)
if(!isturf(T) || T.intact || !T.can_have_cabling())
last = null
return
if(get_dir(last, user) == last.d2)
//Did we just walk backwards? Well, that's the one direction we CAN'T complete a stub.
last = null
return
loaded.cable_join(last, user)
if(is_empty(user))
return //If we've run out, display message and exit
else
last = null
last = loaded.place_turf(get_turf(loc), user, turn(user.dir, 180))
is_empty(user) //If we've run out, display message
/obj/item/rcl/pre_loaded/New() //Comes preloaded with cable, for testing stuff
..()
loaded = new()
loaded.max_amount = max_amount
loaded.amount = max_amount
update_icon(UPDATE_ICON_STATE)
-127
View File
@@ -1,127 +0,0 @@
#define POWER_NONE 0
#define POWER_LOW 50
#define POWER_HIGH 4000
/obj/item/rsf
name = "\improper Rapid-Service-Fabricator"
desc = "A device used to rapidly deploy service items."
icon = 'icons/obj/tools.dmi'
icon_state = "rsf"
item_state = "rsf"
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 0, ACID = 0)
var/atom/currently_dispensing
var/power_mode = POWER_NONE
var/list/rsf_items = list(
"Drinking Glass" = /obj/item/reagent_containers/drinks/drinkingglass,
"Paper" = /obj/item/paper,
"Pen" = /obj/item/pen,
"Dice Pack" = /obj/item/storage/bag/dice,
"Cigarette" = /obj/item/clothing/mask/cigarette,
"Newdles" = /obj/item/food/chinese/newdles,
"Donut" = /obj/item/food/donut,
"Chicken Soup" = /obj/item/reagent_containers/drinks/chicken_soup,
"Tofu Burger" = /obj/item/food/burger/tofu
)
var/static/list/rsf_icons = list(
"Drinking Glass" = image(icon = 'icons/obj/drinks.dmi', icon_state = "glass_empty"),
"Shot Glass" = image(icon = 'icons/obj/drinks.dmi', icon_state = "shotglass"),
"Paper" = image(icon = 'icons/obj/bureaucracy.dmi', icon_state = "paper"),
"Pen" = image(icon = 'icons/obj/bureaucracy.dmi', icon_state = "pen"),
"Dice Pack" = image(icon = 'icons/obj/dice.dmi', icon_state = "dicebag"),
"Cigarette" = image(icon = 'icons/obj/clothing/masks.dmi', icon_state = "cig_on"),
"Newdles" = image(icon = 'icons/obj/food/food.dmi', icon_state = "chinese3"),
"Donut" = image(icon = 'icons/obj/food/bakedgoods.dmi', icon_state = "donut1"),
"Chicken Soup" = image(icon = 'icons/obj/drinks.dmi', icon_state = "soupcan"),
"Tofu Burger" = image(icon = 'icons/obj/food/burgerbread.dmi', icon_state = "tofuburger"),
"Cigar" = image(icon = 'icons/obj/clothing/masks.dmi', icon_state = "cigar_off"),
"Smoked Cheese" = image(icon = 'icons/obj/food/food.dmi', icon_state = "cheesewheel-smoked"),
"Edam Cheese" = image(icon = 'icons/obj/food/food.dmi', icon_state = "cheesewheel-edam"),
"Blue Cheese" = image(icon = 'icons/obj/food/food.dmi', icon_state = "cheesewheel-blue"),
"Camembert Cheese" = image(icon = 'icons/obj/food/food.dmi', icon_state = "cheesewheel-camembert"),
"Caviar" = image(icon = 'icons/obj/food/seafood.dmi', icon_state = "caviar")
)
var/static/list/power_costs = list(
"Drinking Glass" = POWER_LOW,
"Shot Glass" = POWER_LOW,
"Paper" = POWER_LOW,
"Pen" = POWER_LOW,
"Dice Pack" = POWER_LOW,
"Cigarette" = POWER_LOW,
"Newdles" = POWER_HIGH,
"Donut" = POWER_HIGH,
"Chicken Soup" = POWER_HIGH,
"Tofu Burger" = POWER_HIGH,
"Cigar" = POWER_LOW,
"Smoked Cheese" = POWER_HIGH,
"Edam Cheese" = POWER_HIGH,
"Blue Cheese" = POWER_HIGH,
"Camembert Cheese" = POWER_HIGH,
"Caviar" = POWER_HIGH
)
/obj/item/rsf/attack_self__legacy__attackchain(mob/user)
playsound(loc, 'sound/effects/pop.ogg', 50, FALSE)
if(!currently_dispensing)
to_chat(user, "<span class='notice'>Choose an item to dispense!</span>")
else
to_chat(user, "<span class='notice'>You are currently dispensing a [initial(currently_dispensing.name)].</span>")
var/rsf_radial_choice = show_radial_menu(user, src, get_radial_contents())
if(user.stat || !in_range(user, src))
return
currently_dispensing = rsf_items[rsf_radial_choice]
power_mode = power_costs[rsf_radial_choice]
if(currently_dispensing)
to_chat(user, "<span class='notice'>Your RSF has been configured to now dispense a [initial(currently_dispensing.name)]!</span>")
return TRUE
/obj/item/rsf/proc/get_radial_contents()
return rsf_icons & rsf_items
/obj/item/rsf/afterattack__legacy__attackchain(atom/A, mob/user, proximity)
if(!currently_dispensing)
return
if(!proximity)
return
if(!istype(A, /obj/structure/table) && !isfloorturf(A))
return
if(isrobot(user))
var/mob/living/silicon/robot/energy_check = user
if(!energy_check.cell.use(power_mode))
to_chat(user, "<span class='warning'>Insufficient energy.</span>")
flick("[icon_state]_empty", src)
return
var/turf/T = get_turf(A)
if(!istype(T) || T.density)
to_chat(user, "The RSF can only create service items on tables, or floors.")
return
playsound(loc, 'sound/machines/click.ogg', 10, 1)
new currently_dispensing(T)
/obj/item/rsf/executive
name = "\improper Executive-Service-Fabricator"
desc = "A fancier version of the RSF, used to deploy classy refreshments and materials to high ranking clientelle."
icon_state = "rsf-exec"
rsf_items = list(
"Drinking Glass" = /obj/item/reagent_containers/drinks/drinkingglass,
"Shot Glass" = /obj/item/reagent_containers/drinks/drinkingglass/shotglass,
"Paper" = /obj/item/paper,
"Pen" = /obj/item/pen,
"Dice Pack" = /obj/item/storage/bag/dice,
"Cigar" = /obj/item/clothing/mask/cigarette/cigar,
"Cigarette" = /obj/item/clothing/mask/cigarette,
"Smoked Cheese" = /obj/item/food/sliceable/cheesewheel/smoked,
"Edam Cheese" = /obj/item/food/sliceable/cheesewheel/edam,
"Blue Cheese" = /obj/item/food/sliceable/cheesewheel/blue,
"Camembert Cheese" = /obj/item/food/sliceable/cheesewheel/camembert,
"Caviar" = /obj/item/food/caviar,
"Donut" = /obj/item/food/donut
)
#undef POWER_NONE
#undef POWER_LOW
#undef POWER_HIGH
-297
View File
@@ -1,297 +0,0 @@
/obj/item/card/id/syndicate
name = "agent card"
origin_tech = "syndicate=1"
untrackable = TRUE
/// List of access types the agent ID should start off with
var/list/initial_access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_EXTERNAL_AIRLOCKS)
/// Editing is prohibited if registered_human reference is missing
var/mob/living/carbon/human/registered_human
// Static list of all occupations available when changing the occupation on an agent ID
var/static/list/possible_jobs
/// The HUD icon that should be displayed on a mob that is wearing the agent ID
var/hud_icon
COOLDOWN_DECLARE(new_photo_cooldown)
/obj/item/card/id/syndicate/Initialize(mapload)
. = ..()
access = initial_access.Copy()
if(!length(possible_jobs))
possible_jobs = sortTim(GLOB.joblist, GLOBAL_PROC_REF(cmp_text_asc))
/obj/item/card/id/syndicate/Destroy()
registered_human = null
return ..()
/obj/item/card/id/syndicate/researcher
initial_access = list(ACCESS_SYNDICATE)
assignment = "Syndicate Researcher"
icon_state = "syndie"
/obj/item/card/id/syndicate/vox
initial_access = list(ACCESS_MAINT_TUNNELS, ACCESS_VOX, ACCESS_EXTERNAL_AIRLOCKS)
/obj/item/card/id/syndicate/ghost_bar
name = "ghost bar identification card"
assignment = "Ghost Bar Occupant"
initial_access = list() // This is for show, they don't need actual accesses
icon_state = "assistant"
/obj/item/card/id/syndicate/command
initial_access = list(ACCESS_MAINT_TUNNELS, ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER, ACCESS_SYNDICATE_COMMAND, ACCESS_EXTERNAL_AIRLOCKS)
icon_state = "commander"
/obj/item/card/id/syndicate_command
name = "syndicate ID card"
desc = "An ID straight from the Syndicate."
registered_name = "Syndicate"
icon_state = "syndie"
assignment = "Syndicate Overlord"
untrackable = TRUE
can_id_flash = FALSE //This can ID flash, this just prevents it from always flashing.
access = list(ACCESS_SYNDICATE, ACCESS_SYNDICATE_LEADER, ACCESS_SYNDICATE_COMMAND, ACCESS_EXTERNAL_AIRLOCKS)
/obj/item/card/id/syndicate/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(istype(target, /obj/item/card/id))
var/obj/item/card/id/I = target
if(isliving(user) && user?.mind?.special_role)
to_chat(usr, "<span class='notice'>The card's microscanners activate as you pass it over [I], copying its access.</span>")
access |= I.access //Don't copy access if user isn't an antag -- to prevent metagaming
return ITEM_INTERACT_COMPLETE
/obj/item/card/id/syndicate/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
if(!registered_human || !Adjacent(registered_human))
return
. = TRUE
switch(action)
if("delete_info")
delete_info(ui)
if("clear_access")
clear_access()
if("change_ai_tracking")
change_ai_tracking()
if("change_name")
change_name(params["option"], params["name"])
if("change_photo")
change_photo()
if("change_appearance")
change_appearance(params["new_appearance"])
if("change_sex")
change_sex(params["sex"])
if("change_age")
change_age(params["age"])
if("change_occupation")
change_occupation(params["option"])
if("change_money_account")
change_money_account(params["option"], params["new_account"])
if("change_blood_type")
change_blood_type(params["option"], params["new_type"])
if("change_dna_hash")
change_dna_hash(params["option"], params["new_dna"])
if("change_fingerprints")
change_fingerprints(params["option"], params["new_fingerprints"])
RebuildHTML()
/obj/item/card/id/syndicate/ui_data(mob/user)
var/list/data = list()
data["registered_name"] = registered_name
data["sex"] = sex
data["age"] = age
data["assignment"] = assignment
data["job_icon"] = hud_icon
data["associated_account_number"] = associated_account_number
data["blood_type"] = blood_type
data["dna_hash"] = dna_hash
data["fingerprint_hash"] = fingerprint_hash
data["photo"] = photo
data["ai_tracking"] = untrackable
data["photo_cooldown"] = COOLDOWN_FINISHED(src, new_photo_cooldown)
return data
/obj/item/card/id/syndicate/ui_static_data(mob/user)
var/list/data = list()
var/list/idcard_skins = list()
for(var/idcard_skin in get_all_card_skins())
idcard_skins.Add(idcard_skin)
data["appearances"] = idcard_skins
data["id_icon"] = icon
return data
/obj/item/card/id/syndicate/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "AgentCard", name)
ui.open()
/obj/item/card/id/syndicate/activate_self(mob/user)
if(..() || !ishuman(user))
return
if(!registered_human)
registered_human = user
if(registered_human != user)
flash_card(user)
return
switch(tgui_alert(user, "Would you like to display [src] or edit it?", "Choose", list("Edit", "Show")))
if("Show")
flash_card(user)
if("Edit")
ui_interact(user)
/obj/item/card/id/syndicate/proc/delete_info(datum/tgui/ui)
name = initial(name)
registered_name = initial(registered_name)
icon_state = initial(icon_state)
sex = initial(sex)
age = initial(age)
assignment = initial(assignment)
rank = initial(rank)
associated_account_number = initial(associated_account_number)
blood_type = initial(blood_type)
dna_hash = initial(dna_hash)
fingerprint_hash = initial(fingerprint_hash)
photo = null
registered_human.sec_hud_set_ID()
registered_human = null
ui.close()
/obj/item/card/id/syndicate/proc/clear_access()
access = initial_access.Copy() // Initial() doesn't work on lists
to_chat(registered_human, "<span class='notice'>Card access reset.</span>")
/obj/item/card/id/syndicate/proc/change_ai_tracking()
untrackable = !untrackable
/obj/item/card/id/syndicate/proc/change_name(option, name)
var/new_name
if(option == "Primary")
new_name = ishuman(registered_human) ? registered_human.real_name : registered_human.name
else if(option == "Secondary")
new_name = tgui_input_list(registered_human, "Whose name do you want to copy?", "Agent ID - Name", GLOB.crew_list)
if(isnull(new_name))
return
else
new_name = sanitize(name)
registered_name = reject_bad_name(new_name, TRUE)
UpdateName()
to_chat(registered_human, "ID name has been changed to [new_name].")
/obj/item/card/id/syndicate/proc/change_photo()
if(!COOLDOWN_FINISHED(src, new_photo_cooldown))
return
var/job_clothes = null
if(assignment)
job_clothes = assignment
var/icon/newphoto = get_id_photo(registered_human, job_clothes)
if(!newphoto)
return
photo = newphoto
COOLDOWN_START(src, new_photo_cooldown, 10 SECONDS) // This proc is expensive, we don't want people spamming it.
/obj/item/card/id/syndicate/proc/change_appearance(new_appearance)
if(!new_appearance)
return
if(new_appearance in icon_states(icon))
icon_state = new_appearance
/obj/item/card/id/syndicate/proc/change_sex(new_sex)
if(!Adjacent(registered_human) || isnull(new_sex))
return
sex = sanitize(new_sex)
/obj/item/card/id/syndicate/proc/change_age(new_age)
age = clamp(new_age, AGE_MIN, AGE_MAX)
/obj/item/card/id/syndicate/proc/change_occupation(option)
var/new_job
var/new_rank
if(option == "Primary")
new_job = assignment
new_rank = tgui_input_list(registered_human, "What SecHUD icon would you like to be shown on this card?", "Agent Card Occupation", GLOB.joblist + "Prisoner" + "Centcom" + "Solgov" + "Soviet" + "Unknown")
else
var/department = tgui_input_list(registered_human, "Do you want a custom occupation?", "Agent Card Occupation", list("Existing job", "Custom"))
if(department != "Custom")
new_job = tgui_input_list(registered_human, "What job would you like to put on this card?", "Agent Card Occupation", possible_jobs)
new_rank = new_job
else
new_job = sanitize(tgui_input_text(registered_human, "Choose a custom job title:", "Agent Card Occupation", "Assistant", MAX_MESSAGE_LEN))
new_rank = tgui_input_list(registered_human, "What SecHUD icon would you like to be shown on this card?", "Agent Card Occupation", GLOB.joblist + "Prisoner" + "Centcom" + "Solgov" + "Soviet" + "Unknown")
if(!Adjacent(registered_human) || isnull(new_job))
return
assignment = new_job
rank = new_rank
hud_icon = ckey(get_job_name())
UpdateName()
registered_human.sec_hud_set_ID()
/obj/item/card/id/syndicate/proc/change_money_account(option, new_account)
if(option == "Primary")
new_account = registered_human.mind.initial_account?.account_number
if(!new_account)
to_chat(registered_human, "You don't have an account.")
return
else if(option == "Secondary")
new_account = rand(1000, 9999) * 1000 + rand(1000, 9999)
else
new_account = text2num(new_account)
if(!isnum(new_account))
to_chat(registered_human, "ID account number can only contain numbers.")
return
associated_account_number = clamp(new_account, 1000000, 9999999)
to_chat(registered_human, "ID account number has been changed to [new_account].")
/obj/item/card/id/syndicate/proc/change_blood_type(option, new_type)
var/list/possible_blood_types = list("A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-", "Slime Jelly", "None")
if(option == "Primary")
blood_type = registered_human.dna.blood_type
else if(new_type)
if(!(new_type in possible_blood_types))
return
blood_type = new_type
to_chat(registered_human, "ID blood type has been changed to [blood_type].")
/obj/item/card/id/syndicate/proc/change_dna_hash(option, new_dna)
if(option == "Primary")
dna_hash = registered_human.dna.unique_enzymes
else if(option == "Secondary")
dna_hash = md5(num2text(rand(0, 999)))
else
if(new_dna)
dna_hash = sanitize(new_dna, 33) // Max length of 32 characters
/obj/item/card/id/syndicate/proc/change_fingerprints(option, new_fingerprints)
if(option == "Primary")
fingerprint_hash = md5(registered_human.dna.uni_identity)
else if(option == "Secondary")
fingerprint_hash = md5(num2text(rand(0, 999)))
else
var/fingerprints_param = new_fingerprints
if(fingerprints_param)
fingerprint_hash = sanitize(fingerprints_param, 33)
/// like /obj/item/card/id/syndicate, but you can only swipe access, not change your identity, its also trackable
/obj/item/card/id/syndi_scan_only
name = "Syndicate Operative's ID card (Operative)"
rank = "Operative"
assignment = "Operative"
registered_name = "Syndicate Operative"
access = list(ACCESS_SYNDICATE)
/obj/item/card/id/syndi_scan_only/examine(mob/user)
. = ..()
if(isAntag(user))
. += "<span class='notice'>Similar to an agent ID, this ID card can be used to copy accesses, but it lacks the customization and anti-tracking capabilities of an agent ID.</span>"
/obj/item/card/id/syndi_scan_only/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(istype(target, /obj/item/card/id))
var/obj/item/card/id/I = target
if(isliving(user) && user.mind)
if(user.mind.special_role)
to_chat(user, "<span class='notice'>The card's microscanners activate as you pass it over [I], copying its access.</span>")
access |= I.access // Don't copy access if user isn't an antag -- to prevent metagaming
return ITEM_INTERACT_COMPLETE
@@ -1,229 +0,0 @@
/**
* # Implants
*
* Code for implants that can be inserted into a person and have some sort of passive or triggered action.
*
*/
/obj/item/bio_chip
name = "bio-chip"
icon = 'icons/obj/bio_chips.dmi'
icon_state = "generic" //Shows up as a auto surgeon, used as a placeholder when a implant doesn't have a sprite
origin_tech = "materials=2;biotech=3;programming=2"
actions_types = list(/datum/action/item_action/hands_free/activate)
item_color = "black"
flags = DROPDEL // By default, don't let implants be harvestable.
///which implant overlay should be used for implant cases. This should point to a state in bio_chips.dmi
var/implant_state = "implant-default"
/// How the implant is activated.
var/activated = BIOCHIP_ACTIVATED_ACTIVE
/// Whether the implant is implanted. Null if it's never been inserted, TRUE if it's currently inside someone, or FALSE if it's been removed.
var/implanted
/// Who the implant is inside of.
var/mob/living/imp_in
/// Whether multiple implants of this same type can be inserted into someone.
var/allow_multiple = FALSE
/// Amount of times that the implant can be triggered by the user. If the implant can't be used, it can't be inserted.
var/uses = -1
/// List of emote keys that activate this implant when used.
var/list/trigger_emotes
/// What type of action will trigger this emote. Bitfield of IMPLANT_EMOTE_* defines.
var/trigger_causes
/// Whether this implant has already triggered on death or not, to prevent it firing multiple times.
var/has_triggered_on_death = FALSE
///the implant_fluff datum attached to this implant, purely cosmetic "lore" information
var/datum/implant_fluff/implant_data = /datum/implant_fluff
/obj/item/bio_chip/Initialize(mapload)
. = ..()
if(ispath(implant_data))
implant_data = new implant_data
/obj/item/bio_chip/Destroy()
if(imp_in)
removed(imp_in)
QDEL_NULL(implant_data)
return ..()
/obj/item/bio_chip/proc/unregister_emotes()
if(imp_in && LAZYLEN(trigger_emotes))
for(var/emote in trigger_emotes)
UnregisterSignal(imp_in, COMSIG_MOB_EMOTED(emote))
/**
* Set the emote that will trigger the implant.
* * user - User who is trying to associate the implant to themselves.
* * emote_key - Key of the emote that should trigger the implant.
* * on_implant - Whether this proc is being called during the implantation of the implant.
* * silent - If true, the user won't get any to_chat messages if an implantation fails.
*/
/obj/item/bio_chip/proc/set_trigger(mob/user, emote_key, on_implant = FALSE, silent = TRUE)
if(imp_in != user)
return FALSE
if(!emote_key)
return FALSE
if(LAZYIN(trigger_emotes, emote_key) && !on_implant)
if(!silent)
to_chat(user, "<span class='warning'>You've already registered [emote_key]!")
return FALSE
if(emote_key == "me" || emote_key == "custom")
if(!silent)
to_chat(user, "<span class='warning'>You can't trigger [src] with a custom emote.")
return FALSE
if(!(emote_key in user.usable_emote_keys(trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL)))
if(!silent)
to_chat(user, "<span class='warning'>You can't trigger [src] with that emote! Try *help to see emotes you can use.</span>")
return FALSE
if(!(emote_key in user.usable_emote_keys(trigger_causes & BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL)))
CRASH("User was given an bio-chip for an unintentional emote that they can't use.")
LAZYADD(trigger_emotes, emote_key)
RegisterSignal(user, COMSIG_MOB_EMOTED(emote_key), PROC_REF(on_emote))
/obj/item/bio_chip/proc/on_emote(mob/living/user, datum/emote/fired_emote, key, emote_type, message, intentional)
SIGNAL_HANDLER
if(!implanted || !imp_in)
return
if(!(intentional && (trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL)) && !(!intentional && (trigger_causes & BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL)))
return
add_attack_logs(user, user, "[intentional ? "intentionally" : "unintentionally"] [src] was [intentional ? "intentionally" : "unintentionally"] triggered with the emote [fired_emote].")
emote_trigger(key, user, intentional)
/obj/item/bio_chip/proc/on_death(mob/source, gibbed)
SIGNAL_HANDLER
if(!implanted || !imp_in)
return
if(gibbed && (trigger_causes & BIOCHIP_TRIGGER_NOT_WHEN_GIBBED))
return
// This should help avoid infinite recursion for things like dust that call death()
if(has_triggered_on_death && (trigger_causes & BIOCHIP_TRIGGER_DEATH_ONCE))
return
has_triggered_on_death = TRUE
add_attack_logs(source, source, "had their [src] bio-chip triggered on [gibbed ? "gib" : "death"].")
death_trigger(source, gibbed)
/obj/item/bio_chip/proc/emote_trigger(emote, mob/source, force)
return
/obj/item/bio_chip/proc/death_trigger(mob/source, gibbed)
return
/obj/item/bio_chip/proc/activate(cause)
SEND_SIGNAL(src, COMSIG_IMPLANT_ACTIVATED, cause, imp_in)
return
/obj/item/bio_chip/ui_action_click()
activate("action_button")
/**
* Try to implant ourselves into a mob.
*
* * source - The person the implant is being administered to.
* * user - The person who is doing the implanting.
*
* Returns
* 1 if the implant injects successfully
* -1 if the implant fails to inject
* 0 if there's no room for the implant.
*/
/obj/item/bio_chip/proc/implant(mob/source, mob/user, force)
if(!force && !can_implant(source, user))
return
var/obj/item/bio_chip/imp_e = locate(type) in source
if(!allow_multiple && imp_e && imp_e != src)
if(imp_e.uses < initial(imp_e.uses)*2)
if(uses == -1)
imp_e.uses = -1
else
imp_e.uses = min(imp_e.uses + uses, initial(imp_e.uses)*2)
qdel(src)
return 1
else
return 0
loc = source
imp_in = source
implanted = TRUE
if(trigger_emotes)
if(!(trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL | BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL))
CRASH("Bio-chip [src] has trigger emotes defined but no trigger cause with which to use them!")
if(!activated && (trigger_causes & BIOCHIP_EMOTE_TRIGGER_INTENTIONAL))
CRASH("Bio-chip [src] has intentional emote triggers on a passive bio-chip")
// If you can't activate the implant manually, you shouldn't be able to deliberately activate it with an emote
for(var/emote in trigger_emotes)
set_trigger(source, emote, TRUE, TRUE)
if(activated)
for(var/X in actions)
var/datum/action/A = X
A.Grant(source)
if(trigger_causes & (BIOCHIP_TRIGGER_DEATH_ONCE | BIOCHIP_TRIGGER_DEATH_ANY))
RegisterSignal(source, COMSIG_MOB_DEATH, PROC_REF(on_death))
if(ishuman(source))
var/mob/living/carbon/human/H = source
H.sec_hud_set_implants()
if(user)
add_attack_logs(user, source, "Chipped with [src]")
SEND_SIGNAL(src, COMSIG_IMPLANT_IMPLANTED, source, user, force)
return 1
/**
* Check that we can actually implant this before implanting it
* * source - The person being implanted
* * user - The person doing the implanting
*
* Returns
* TRUE - I could care less, implant it, maybe don't. I don't care.
* FALSE - Don't implant!
*/
/obj/item/bio_chip/proc/can_implant(mob/source, mob/user)
return TRUE
/**
* Clean up when an implant is removed.
* * source - the user who the implant was removed from.
*/
/obj/item/bio_chip/proc/removed(mob/source)
loc = null
imp_in = null
implanted = FALSE
for(var/X in actions)
var/datum/action/A = X
A.Remove(source)
if(ishuman(source))
var/mob/living/carbon/human/H = source
H.sec_hud_set_implants()
if(trigger_causes & (BIOCHIP_TRIGGER_DEATH_ONCE | BIOCHIP_TRIGGER_DEATH_ANY))
UnregisterSignal(source, COMSIG_MOB_DEATH)
unregister_emotes()
SEND_SIGNAL(src, COMSIG_IMPLANT_REMOVED, source)
return TRUE
/obj/item/bio_chip/dropped(mob/user)
. = TRUE
..()
@@ -1,61 +0,0 @@
/obj/item/bio_chip/abductor
name = "recall bio-chip"
desc = "Returns you to the mothership."
icon = 'icons/obj/abductor.dmi'
icon_state = "implant"
origin_tech = "materials=2;biotech=7;magnets=4;bluespace=4;abductor=5"
implant_data = /datum/implant_fluff/abductor
implant_state = "implant-alien"
var/obj/machinery/abductor/pad/home
var/cooldown = 30
var/total_cooldown = 30
/obj/item/bio_chip/abductor/activate()
if(cooldown == total_cooldown)
if(imp_in.has_status_effect(STATUS_EFFECT_ABDUCTOR_COOLDOWN))
to_chat(imp_in, "<span class='warning'>The teleporter will not activate yet to prevent potential damage!</span>")
return
home.Retrieve(imp_in, 1)
cooldown = 0
START_PROCESSING(SSobj, src)
else
to_chat(imp_in, "<span class='warning'>You must wait [(total_cooldown - cooldown) * 2] seconds to use [src] again!</span>")
/obj/item/bio_chip/abductor/process()
if(cooldown < total_cooldown)
cooldown++
if(cooldown == total_cooldown)
STOP_PROCESSING(SSobj, src)
/obj/item/bio_chip/abductor/implant(mob/source, mob/user)
if(..())
var/obj/machinery/abductor/console/console
if(ishuman(source))
var/mob/living/carbon/human/H = source
if(isabductor(H))
var/datum/species/abductor/S = H.dna.species
console = get_team_console(S.team)
home = console.pad
if(!home)
console = get_team_console(pick(1, 2, 3, 4))
home = console.pad
return TRUE
/obj/item/bio_chip/abductor/proc/get_team_console(team)
var/obj/machinery/abductor/console/console
for(var/obj/machinery/abductor/console/c in GLOB.abductor_equipment)
if(c.team == team)
console = c
break
return console
/obj/item/bio_chip_implanter/abductor
name = "bio-chip implanter (abductor)"
implant_type = /obj/item/bio_chip/abductor
/obj/item/bio_chip_case/abductor
name = "bio-chip case - 'abductor'"
desc = "A glass case containing an abductor bio-chip."
implant_type = /obj/item/bio_chip/abductor
@@ -1,101 +0,0 @@
/obj/item/bio_chip/adrenalin
name = "adrenal bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=2;biotech=4;combat=3;syndicate=4"
uses = 3
implant_data = /datum/implant_fluff/adrenaline
implant_state = "implant-syndicate"
/obj/item/bio_chip/adrenalin/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel a sudden surge of energy!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.adjustStaminaLoss(-75)
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("synaptizine", 10)
imp_in.reagents.add_reagent("omnizine_no_addiction", 10)
imp_in.reagents.add_reagent("stimulative_agent", 10)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/adrenalin
name = "bio-chip implanter (adrenalin)"
implant_type = /obj/item/bio_chip/adrenalin
/obj/item/bio_chip_case/adrenaline
name = "bio-chip case - 'Adrenaline'"
desc = "A glass case containing an adrenaline bio-chip."
implant_type = /obj/item/bio_chip/adrenalin
/obj/item/bio_chip/basic_adrenalin
name = "basic adrenal bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=2;biotech=4;combat=3;syndicate=3"
uses = 1
implant_data = /datum/implant_fluff/basic_adrenalin
implant_state = "implant-syndicate"
/obj/item/bio_chip/basic_adrenalin/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel a sudden surge of energy!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.adjustStaminaLoss(-75)
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("synaptizine", 7.5)
imp_in.reagents.add_reagent("weak_omnizine", 7.5)
imp_in.reagents.add_reagent("stimulative_agent", 7.5)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/basic_adrenalin
name = "bio-chip implanter (basic adrenalin)"
implant_type = /obj/item/bio_chip/basic_adrenalin
/obj/item/bio_chip_case/basic_adrenalin
name = "bio-chip case - 'Basic Adrenaline'"
desc = "A glass case containing an smaller than normal adrenaline bio-chip."
implant_type = /obj/item/bio_chip/basic_adrenalin
/obj/item/bio_chip/proto_adrenalin
name = "proto-adrenal bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=2;biotech=4;combat=3;syndicate=2"
uses = 1
implant_data = /datum/implant_fluff/proto_adrenaline
implant_state = "implant-syndicate"
/obj/item/bio_chip/proto_adrenalin/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel a sudden surge of energy!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.setStaminaLoss(0) //Since it doesn't have a good followup like adrenals, and getting batoned the moment after triggering it will stamina crit you, will set to zero over - 75
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("stimulative_cling", 1)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/proto_adrenalin
name = "bio-chip implanter (proto-adrenalin)"
implant_type = /obj/item/bio_chip/proto_adrenalin
/obj/item/bio_chip_case/proto_adrenalin
name = "bio-chip case - 'proto-adrenalin'"
desc = "A glass case containing an proto-adrenalin bio-chip."
implant_type = /obj/item/bio_chip/proto_adrenalin
@@ -1,68 +0,0 @@
/obj/item/bio_chip_case
name = "bio-chip case"
desc = "A glass case containing a bio-chip."
icon = 'icons/obj/bio_chips.dmi'
icon_state = "implantcase"
item_state = "implantcase"
throw_range = 5
w_class = WEIGHT_CLASS_TINY
origin_tech = "materials=1;biotech=2"
container_type = OPENCONTAINER | INJECTABLE | DRAWABLE
materials = list(MAT_GLASS = 500)
var/obj/item/bio_chip/imp
var/obj/item/bio_chip/implant_type
/obj/item/bio_chip_case/Initialize(mapload)
. = ..()
if(!implant_type)
return
imp = new implant_type(src)
update_state()
/obj/item/bio_chip_case/Destroy()
if(imp)
QDEL_NULL(imp)
return ..()
/obj/item/bio_chip_case/proc/update_state()
if(imp)
origin_tech = imp.origin_tech
flags = imp.flags & ~DROPDEL
reagents = imp.reagents
else
origin_tech = initial(origin_tech)
flags = initial(flags)
reagents = null
update_icon(UPDATE_OVERLAYS)
/obj/item/bio_chip_case/update_overlays()
. = ..()
if(imp)
var/image/implant_overlay = image('icons/obj/bio_chips.dmi', imp.implant_state)
. += implant_overlay
/obj/item/bio_chip_case/attackby__legacy__attackchain(obj/item/W, mob/user)
..()
if(is_pen(W))
rename_interactive(user, W)
else if(istype(W, /obj/item/bio_chip_implanter))
var/obj/item/bio_chip_implanter/I = W
if(I.imp)
if(imp || I.imp.implanted)
return
I.imp.forceMove(src)
imp = I.imp
I.imp = null
update_state()
I.update_icon(UPDATE_ICON_STATE)
else
if(imp)
if(I.imp)
return
imp.loc = I
I.imp = imp
imp = null
update_state()
I.update_icon(UPDATE_ICON_STATE)
@@ -1,52 +0,0 @@
/obj/item/bio_chip/chem
name = "chem bio-chip"
desc = "Injects things."
icon_state = "reagents"
origin_tech = "materials=3;biotech=4"
container_type = OPENCONTAINER
trigger_causes = BIOCHIP_TRIGGER_DEATH_ANY
implant_data = /datum/implant_fluff/chem
implant_state = "implant-nanotrasen"
/obj/item/bio_chip/chem/Initialize(mapload)
. = ..()
create_reagents(50)
GLOB.tracked_implants += src
/obj/item/bio_chip/chem/Destroy()
GLOB.tracked_implants -= src
return ..()
/obj/item/bio_chip/chem/death_trigger(mob/victim, gibbed)
activate(reagents.total_volume)
/obj/item/bio_chip/chem/activate(cause)
if(!cause || !imp_in)
return FALSE
var/mob/living/carbon/R = imp_in
var/injectamount
var/list/implant_chems = list()
for(var/datum/reagent/chems in reagents.reagent_list)
implant_chems += chems.name
var/contained_chemicals = english_list(implant_chems)
if(cause == "action_button")
injectamount = reagents.total_volume
else
injectamount = cause
reagents.trans_to(R, injectamount)
add_attack_logs(usr, R, "Chem bio-chip activated injecting [injectamount]u of [contained_chemicals]")
to_chat(R, "<span class='italics'>You hear a faint beep.</span>")
if(!reagents.total_volume)
to_chat(R, "<span class='italics'>You hear a faint click from your chest.</span>")
qdel(src)
/obj/item/bio_chip_implanter/chem
name = "bio-chip implanter (chem)"
implant_type = /obj/item/bio_chip/chem
/obj/item/bio_chip_case/chem
name = "bio-chip case - 'Remote Chemical'"
desc = "A glass case containing a remote chemical bio-chip."
implant_type = /obj/item/bio_chip/chem
@@ -1,68 +0,0 @@
/obj/item/bio_chip/death_alarm
name = "death alarm bio-chip"
desc = "An alarm which monitors host vital signs and transmits a radio message upon death."
activated = BIOCHIP_ACTIVATED_PASSIVE
trigger_causes = BIOCHIP_TRIGGER_DEATH_ANY
implant_data = /datum/implant_fluff/death_alarm
implant_state = "implant-nanotrasen"
var/mobname = "Unknown"
var/static/list/stealth_areas = typecacheof(list(/area/syndicate_mothership, /area/shuttle/syndicate_elite))
/// Tracking to prevent multiple EMPs in the same tick from flooding radio.
COOLDOWN_DECLARE(emp_spam_lock)
/obj/item/bio_chip/death_alarm/implant(mob/target)
. = ..()
if(.)
mobname = target.real_name
/obj/item/bio_chip/death_alarm/activate(cause) // Death signal sends name followed by the gibbed / not gibbed check
var/mob/M = imp_in
var/area/t = get_area(M)
var/obj/item/radio/headset/a = new /obj/item/radio/headset(src)
a.follow_target = M
switch(cause)
if("gib")
a.autosay("[mobname] has died-zzzzt in-in-in...", "[mobname]'s Death Alarm")
qdel(src)
if("emp")
if(!COOLDOWN_FINISHED(src, emp_spam_lock))
return
var/name = prob(50) ? t.name : pick(SSmapping.teleportlocs)
a.autosay("[mobname] has died in [name]!", "[mobname]'s Death Alarm")
COOLDOWN_START(src, emp_spam_lock, 0.1 SECONDS)
else
if(is_type_in_typecache(t, stealth_areas))
//give the syndies a bit of stealth
a.autosay("[mobname] has died in Space!", "[mobname]'s Death Alarm")
else
a.autosay("[mobname] has died in [t.name]!", "[mobname]'s Death Alarm")
qdel(src)
qdel(a)
/obj/item/bio_chip/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this
activate("emp") //let's shout that this dude is dead
/obj/item/bio_chip/death_alarm/death_trigger(mob/source, gibbed)
if(gibbed)
activate("gib")
else
activate("death")
/obj/item/bio_chip/death_alarm/removed(mob/target)
if(..())
UnregisterSignal(target, COMSIG_MOB_DEATH)
return TRUE
return FALSE
/obj/item/bio_chip_implanter/death_alarm
name = "bio-chip implanter (Death Alarm)"
implant_type = /obj/item/bio_chip/death_alarm
/obj/item/bio_chip_case/death_alarm
name = "bio-chip Case - 'Death Alarm'"
desc = "A case containing a death alarm bio-chip."
implant_type = /obj/item/bio_chip/death_alarm
@@ -1,76 +0,0 @@
/datum/deathrattle_group
var/name
var/list/implants = list()
/datum/deathrattle_group/New(name)
if(name)
src.name = name
else
// Give the group a unique name for debugging, and possible future
// use for making custom linked groups.
src.name = "[rand(100, 999)] [pick(GLOB.phonetic_alphabet)]"
/*
* Proc called by new implant being added to the group. Listens for the
* implant being implanted, removed and destroyed.
*
* If implant is already implanted in a person, then trigger the implantation
* code.
*/
/datum/deathrattle_group/proc/register(obj/item/bio_chip/deathrattle/implant)
if(implant in implants)
return
RegisterSignal(implant, COMSIG_PARENT_QDELETING, PROC_REF(on_implant_destruction))
RegisterSignal(implant, COMSIG_IMPLANT_ACTIVATED, PROC_REF(on_user_death))
implants += implant
/datum/deathrattle_group/proc/on_implant_destruction(obj/item/bio_chip/implant)
SIGNAL_HANDLER
implants -= implant
/datum/deathrattle_group/proc/on_user_death(obj/item/bio_chip/implant, source, mob/owner)
SIGNAL_HANDLER
var/victim_name = owner.mind ? owner.mind.name : owner.real_name
// All "hearers" hear the same sound.
var/sound = pick(
'sound/items/knell1.ogg',
'sound/items/knell2.ogg',
'sound/items/knell3.ogg',
'sound/items/knell4.ogg',
)
for(var/obj/item/bio_chip/deathrattle/other_implant as anything in implants)
// Skip the unfortunate soul, and any unimplanted implants
if(implant == other_implant || !implant.imp_in)
continue
var/mob/living/recipient = other_implant.imp_in
to_chat(recipient, "<i>You hear a strange, robotic voice in your head...</i> <span class='robot'>\"<b>[victim_name]</b> has died...\"</span>")
recipient.playsound_local(get_turf(recipient), sound, vol = 75, vary = FALSE, pressure_affected = FALSE, use_reverb = FALSE)
qdel(implant)
/obj/item/bio_chip/deathrattle
name = "deathrattle implant"
desc = "Hope no one else dies, prepare for when they do."
activated = BIOCHIP_ACTIVATED_PASSIVE
trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE
implant_data = /datum/implant_fluff/deathrattle
implant_state = "implant-nanotrasen"
actions_types = null
/obj/item/bio_chip/deathrattle/emp_act(severity)
activate("emp")
/obj/item/bio_chip/deathrattle/death_trigger(mob/source, gibbed)
activate("death")
/obj/item/bio_chip_case/deathrattle
name = "implant case - 'Deathrattle'"
desc = "A glass case containing a deathrattle implant."
implant_type = /obj/item/bio_chip/deathrattle
@@ -1,34 +0,0 @@
// Dust implant, for CC officers. Prevents gear theft if they die.
/obj/item/bio_chip/dust
name = "duster bio-chip"
desc = "A remote controlled bio-chip that will dust the user upon activation (or death of user)."
icon_state = "dust"
actions_types = list(/datum/action/item_action/hands_free/activate/always)
trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE | BIOCHIP_TRIGGER_NOT_WHEN_GIBBED
implant_data = /datum/implant_fluff/dust
implant_state = "implant-nanotrasen"
/obj/item/bio_chip/dust/death_trigger(mob/source, force)
activate("death")
/obj/item/bio_chip/dust/activate(cause)
if(!cause || !imp_in || cause == "emp")
return FALSE
if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your dusting bio-chip? This will turn you to ash!", "Dusting Confirmation", "Yes", "No") != "Yes")
return FALSE
to_chat(imp_in, "<span class='notice'>Your dusting bio-chip activates!</span>")
imp_in.visible_message("<span class = 'warning'>[imp_in] burns up in a flash!</span>")
imp_in.dust()
/obj/item/bio_chip/dust/emp_act(severity)
return
/obj/item/bio_chip_implanter/dust
name = "bio-chip implanter (Dust-on-death)"
implant_type = /obj/item/bio_chip/dust
/obj/item/bio_chip_case/dust
name = "bio-chip case - 'Dust'"
desc = "A glass case containing a dust bio-chip."
implant_type = /obj/item/bio_chip/dust
@@ -1,23 +0,0 @@
/obj/item/bio_chip/emp
name = "emp bio-chip"
desc = "Triggers an EMP."
icon_state = "emp"
origin_tech = "biotech=3;magnets=4;syndicate=1"
uses = 2
implant_data = /datum/implant_fluff/emp
implant_state = "implant-syndicate"
/obj/item/bio_chip/emp/activate()
uses--
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(empulse), get_turf(imp_in), 3, 5, 1)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/emp
name = "bio-chip implanter (EMP)"
implant_type = /obj/item/bio_chip/emp
/obj/item/bio_chip_case/emp
name = "bio-chip case - 'EMP'"
desc = "A glass case containing an EMP bio-chip."
implant_type = /obj/item/bio_chip/emp
@@ -1,147 +0,0 @@
/obj/item/bio_chip/explosive
name = "microbomb bio-chip"
desc = "And boom goes the weasel."
icon_state = "explosive"
origin_tech = "materials=2;combat=3;biotech=4;syndicate=4"
actions_types = list(/datum/action/item_action/hands_free/activate/always)
trigger_causes = BIOCHIP_TRIGGER_DEATH_ONCE // Not surviving that
implant_data = /datum/implant_fluff/explosive
implant_state = "implant-syndicate"
var/detonating = FALSE
var/weak = 2
var/medium = 0.8
var/heavy = 0.4
var/delay = 7
/obj/item/bio_chip/explosive/death_trigger(mob/source, gibbed)
activate("death")
/obj/item/bio_chip/explosive/activate(cause)
if(!cause || !imp_in)
return FALSE
if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your microbomb bio-chip? This will cause you to explode!", "Microbomb Bio-chip Confirmation", "Yes", "No") != "Yes")
return FALSE
if(detonating)
return FALSE
heavy = round(heavy)
medium = round(medium)
weak = round(weak)
detonating = TRUE
to_chat(imp_in, "<span class='danger'>You activate your microbomb bio-chip.</span>")
//If the delay is short, just blow up already jeez
if(delay <= 7)
self_destruct()
return
timed_explosion()
/// Gib the implantee and delete their destructible contents.
/obj/item/bio_chip/explosive/proc/self_destruct()
if(!imp_in)
return
explosion(src, heavy, medium, weak, weak, flame_range = weak, cause = name)
// In case something happens to the implantee between now and the
// self-destruct
var/current_location = get_turf(imp_in)
var/list/destructed_items = list()
// Iterate over the implantee's contents and take out indestructible
// things to avoid having to worry about containers and recursion
for(var/obj/item/I in imp_in.get_contents())
if(I == src) // Don't delete ourselves prematurely
continue
// Drop indestructible items on the ground first, to avoid them
// getting deleted when destroying the rest of the items, which we
// track in a list to qdel afterwards
if(I.resistance_flags & INDESTRUCTIBLE)
I.forceMove(current_location)
else
destructed_items += I
QDEL_LIST_CONTENTS(destructed_items)
imp_in.gib()
qdel(src)
/obj/item/bio_chip/explosive/implant(mob/source)
var/obj/item/bio_chip/explosive/imp_e = locate(type) in source
if(imp_e && imp_e != src)
imp_e.heavy += heavy
imp_e.medium += medium
imp_e.weak += weak
imp_e.delay += delay
qdel(src)
return TRUE
return ..()
/obj/item/bio_chip/explosive/proc/timed_explosion()
imp_in.visible_message("<span class = 'warning'>[imp_in] starts beeping ominously!</span>")
playsound(loc, 'sound/items/timer.ogg', 30, 0)
var/wait_delay = delay / 4
sleep(wait_delay)
if(imp_in && imp_in.stat)
imp_in.visible_message("<span class = 'warning'>[imp_in] doubles over in pain!</span>")
imp_in.Weaken(14 SECONDS)
playsound(loc, 'sound/items/timer.ogg', 30, 0)
sleep(wait_delay)
playsound(loc, 'sound/items/timer.ogg', 30, 0)
sleep(wait_delay)
playsound(loc, 'sound/items/timer.ogg', 30, 0)
sleep(wait_delay)
self_destruct()
/obj/item/bio_chip/explosive/macro
name = "macrobomb bio-chip"
desc = "And boom goes the weasel. And everything else nearby."
origin_tech = "materials=3;combat=5;biotech=4;syndicate=5"
weak = 16
medium = 8
heavy = 4
delay = 3 SECONDS
implant_data = new /datum/implant_fluff/explosive_macro
/obj/item/bio_chip/explosive/macro/activate(cause)
if(!cause || !imp_in)
return FALSE
if(cause == "action_button" && alert(imp_in, "Are you sure you want to activate your macrobomb bio-chip? This will cause you to explode and gib!", "Macrobomb Bio-chip Confirmation", "Yes", "No") != "Yes")
return FALSE
to_chat(imp_in, "<span class='notice'>You activate your macrobomb bio-chip.</span>")
timed_explosion()
/obj/item/bio_chip/explosive/macro/implant(mob/source)
var/obj/item/bio_chip/explosive/imp_e = locate(type) in source
if(imp_e && imp_e != src)
return FALSE
imp_e = locate(/obj/item/bio_chip/explosive) in source
if(imp_e && imp_e != src)
heavy += imp_e.heavy
medium += imp_e.medium
weak += imp_e.weak
delay += imp_e.delay
qdel(imp_e)
return ..()
/obj/item/bio_chip_implanter/explosive
name = "bio-chip implanter (explosive)"
implant_type = /obj/item/bio_chip/explosive
/obj/item/bio_chip_case/explosive
name = "bio-chip case - 'Micro Explosive'"
desc = "A glass case containing a micro explosive bio-chip."
implant_type = /obj/item/bio_chip/explosive
/obj/item/bio_chip_implanter/explosive_macro
name = "bio-chip implanter (macro-explosive)"
implant_type = /obj/item/bio_chip/explosive/macro
/obj/item/bio_chip_case/explosive_macro
name = "bio-chip case - 'Macro Explosive'"
desc = "A glass case containing a macro explosive bio-chip."
implant_type = /obj/item/bio_chip/explosive/macro
@@ -1,26 +0,0 @@
/// Dumb path but easier to search for admins
/obj/item/bio_chip/gorilla_rampage
name = "magillitis serum bio-chip"
desc = "An experimental biochip which causes irreversable rapid muscular growth in Hominidae. Side-affects may include hypertrichosis, violent outbursts, and an unending affinity for bananas."
icon_state = "gorilla_rampage"
origin_tech = "combat=5;biotech=5;syndicate=2"
uses = 1
implant_data = /datum/implant_fluff/gorilla_rampage
implant_state = "implant-syndicate"
/obj/item/bio_chip/gorilla_rampage/activate()
if(!iscarbon(imp_in))
return
var/mob/living/carbon/target = imp_in
target.visible_message("<span class='userdanger'>[target] swells and their hair grows rapidly. Uh oh!.</span>","<span class='userdanger'>You feel your muscles swell and your hair grow as you return to monke.</span>", "<span class='userdanger'>You hear angry gorilla noises.</span>")
target.gorillize(TRUE)
/obj/item/bio_chip_implanter/gorilla_rampage
name = "bio-chip implanter (magillitis serum)"
implant_type = /obj/item/bio_chip/gorilla_rampage
/obj/item/bio_chip_case/gorilla_rampage
name = "bio-chip case - 'magillitis serum'"
desc = "A glass case containing a magillitis bio-chip."
implant_type = /obj/item/bio_chip/gorilla_rampage
@@ -1,27 +0,0 @@
/obj/item/bio_chip/krav_maga
name = "krav maga bio-chip"
desc = "Teaches you the arts of Krav Maga in 5 short instructional videos beamed directly into your eyeballs."
icon = 'icons/obj/wizard.dmi'
icon_state ="scroll2"
origin_tech = "materials=2;biotech=4;combat=5;syndicate=4"
implant_data = /datum/implant_fluff/krav_maga
var/datum/martial_art/krav_maga/style = new
/obj/item/bio_chip/krav_maga/activate()
var/mob/living/carbon/human/H = imp_in
if(!ishuman(H) || !H.mind)
return
if(istype(H.mind.martial_art, /datum/martial_art/krav_maga))
style.remove(H)
else
style.teach(H, TRUE)
/obj/item/bio_chip_implanter/krav_maga
name = "bio-chip implanter (krav maga)"
implant_type = /obj/item/bio_chip/krav_maga
/obj/item/bio_chip_case/krav_maga
name = "bio-chip case - 'Krav Maga'"
desc = "A glass case containing a bio-chip that can teach the user the art of Krav Maga."
implant_type = /obj/item/bio_chip/krav_maga
@@ -1,43 +0,0 @@
/obj/item/bio_chip/mindshield
name = "mindshield bio-chip"
desc = "Stops people messing with your mind."
origin_tech = "materials=2;biotech=4;programming=4"
activated = BIOCHIP_ACTIVATED_PASSIVE
implant_data = /datum/implant_fluff/mindshield
implant_state = "implant-nanotrasen"
/obj/item/bio_chip/mindshield/can_implant(mob/source, mob/user)
if(source.mind?.has_antag_datum(/datum/antagonist/rev/head))
source.visible_message("<span class='biggerdanger'>[source] seems to resist [src]!</span>",
"<span class='warning'>You feel something interfering with your mental conditioning, but you resist it!</span>")
return FALSE
return ..()
/obj/item/bio_chip/mindshield/implant(mob/target)
if(!..())
return FALSE
if(target.mind)
if(target.mind.has_antag_datum(/datum/antagonist/rev))
SSticker.mode.remove_revolutionary(target.mind)
if(IS_CULTIST(target))
to_chat(target, "<span class='warning'>You feel the corporate tendrils of Nanotrasen try to invade your mind!</span>")
return TRUE
to_chat(target, "<span class='notice'>Your mind feels hardened - more resistant to brainwashing.</span>")
return TRUE
/obj/item/bio_chip/mindshield/removed(mob/target, silent = 0)
if(..())
if(target.stat != DEAD && !silent)
to_chat(target, "<span class='boldnotice'>Your mind softens. You feel susceptible to the effects of brainwashing once more.</span>")
return TRUE
return FALSE
/obj/item/bio_chip_implanter/mindshield
name = "bio-chip implanter (mindshield)"
implant_type = /obj/item/bio_chip/mindshield
/obj/item/bio_chip_case/mindshield
name = "bio-chip case - 'mindshield'"
desc = "A glass case containing a mindshield bio-chip."
implant_type = /obj/item/bio_chip/mindshield
@@ -1,120 +0,0 @@
/obj/item/bio_chip_pad
name = "bio-chip pad"
desc = "Used to modify bio-chips."
icon = 'icons/obj/bio_chips.dmi'
icon_state = "implantpad-off"
item_state = "electronic"
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
var/obj/item/bio_chip_case/case
var/static/list/cached_base64_icons = list()
/obj/item/bio_chip_pad/Destroy()
if(case)
eject_case()
return ..()
/obj/item/bio_chip_pad/examine(mob/user)
. = ..()
. += "<span class='notice'>You can <b>Alt-Click</b> [src] to remove it's stored implant.</span>"
/obj/item/bio_chip_pad/update_icon_state()
if(case)
icon_state = "implantpad-on"
else
icon_state = "implantpad-off"
/obj/item/bio_chip_pad/attack_self__legacy__attackchain(mob/user)
ui_interact(user)
/obj/item/bio_chip_pad/attackby__legacy__attackchain(obj/item/bio_chip_case/C, mob/user)
if(istype(C))
addcase(user, C)
else
return ..()
/obj/item/bio_chip_pad/proc/addcase(mob/user, obj/item/bio_chip_case/C)
if(!user || !C)
return
if(case)
to_chat(user, "<span class='warning'>There's already a bio-chip in the pad!</span>")
return
user.unequip(C)
C.forceMove(src)
case = C
update_icon(UPDATE_ICON_STATE)
SStgui.update_uis(src)
/obj/item/bio_chip_pad/proc/eject_case(mob/user)
if(!case)
return
if(user)
if(user.put_in_hands(case))
add_fingerprint(user)
case.add_fingerprint(user)
case = null
update_icon(UPDATE_ICON_STATE)
SStgui.update_uis(src)
/obj/item/bio_chip_pad/AltClick(mob/user)
if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user))
return
eject_case(user)
/obj/item/bio_chip_pad/ui_state(mob/user)
return GLOB.default_state
/obj/item/bio_chip_pad/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "BioChipPad", name)
ui.set_autoupdate(FALSE)
ui.open()
/obj/item/bio_chip_pad/ui_data(mob/user)
var/list/data = list()
data["contains_case"] = case ? TRUE : FALSE
if(case && case.imp)
var/datum/implant_fluff/implant_data = case.imp.implant_data
var/icon/base64icon = cached_base64_icons["[initial(case.imp.icon)][initial(case.imp.icon_state)]"]
if(!base64icon)
base64icon = "[icon2base64(icon(initial(case.imp.icon), initial(case.imp.icon_state), SOUTH, 1))]"
cached_base64_icons["[initial(case.imp.icon)][initial(case.imp.icon_state)]"] = base64icon
data["implant"] = list(
"name" = implant_data.name,
"life" = implant_data.life,
"notes" = implant_data.notes,
"function" = implant_data.function,
"image" = "[icon2base64(icon(initial(case.imp.icon), initial(case.imp.icon_state), SOUTH, 1))]",
)
if(istype(case.imp, /obj/item/bio_chip/tracking))
var/obj/item/bio_chip/tracking/T = case.imp
data["gps"] = T
data["tag"] = T.gpstag
else
data["gps"] = null
data["tag"] = null
else
// Sanity check in the case that a pad is used for multiple types of implants.
data["gps"] = null
data["tag"] = null
return data
/obj/item/bio_chip_pad/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
if(..())
return
. = TRUE
switch(action)
if("eject_case")
eject_case(ui.user)
if("tag")
var/obj/item/bio_chip/tracking/T = case.imp
var/newtag = params["newtag"] || ""
newtag = uppertext(paranoid_sanitize(copytext_char(newtag, 1, 5)))
if(!length(newtag) || T.gpstag == newtag)
return
T.gpstag = newtag
@@ -1,47 +0,0 @@
/obj/item/bio_chip/grey_autocloner
name = "technocracy cloning bio-chip"
desc = "Allows for advanced instantanious cloning!"
origin_tech = "materials=3;combat=5;syndicate=2"
activated = FALSE
trigger_causes = BIOCHIP_TRIGGER_DEATH_ANY
implant_state = "implant-alien"
var/obj/machinery/grey_autocloner/linked
var/datum/dna2_record/our_record
/obj/item/bio_chip/grey_autocloner/Destroy()
linked = null
our_record = null
return ..()
/obj/item/bio_chip/grey_autocloner/death_trigger(mob/source, gibbed)
imp_in.ghostize(TRUE)
if(linked)
linked.growclone(our_record)
/obj/item/bio_chip/grey_autocloner/implant(mob/source, mob/user, force)
if(!linked)
to_chat(user, "<span class='warning'>Please link the implanter with a Technocracy cloning pod!</span>")
return FALSE
. = ..()
if(!. || !ishuman(imp_in))
return FALSE
our_record = new /datum/dna2_record()
our_record.ckey = imp_in.ckey
var/obj/item/organ/B = imp_in.get_int_organ(/obj/item/organ/internal/brain)
B.dna.check_integrity()
our_record.dna = B.dna.Clone()
our_record.id = copytext(md5(B.dna.real_name), 2, 6)
our_record.name = B.dna.real_name
our_record.types = DNA2_BUF_UI|DNA2_BUF_UE|DNA2_BUF_SE
our_record.languages = imp_in.languages
if(imp_in.mind) //Save that mind so traitors can continue traitoring after cloning.
our_record.mind = imp_in.mind.UID()
/obj/item/bio_chip_implanter/grey_autocloner
name = "bio-chip implanter (Technocracy cloning)"
implant_type = /obj/item/bio_chip/grey_autocloner
/obj/item/bio_chip_case/grey_autocloner
name = "bio-chip case - 'Technocracy cloning'"
desc = "A glass case containing an Technocracy bio-chip."
implant_type = /obj/item/bio_chip/grey_autocloner
@@ -1,27 +0,0 @@
/obj/item/bio_chip/sad_trombone
name = "sad trombone bio-chip"
activated = FALSE
trigger_emotes = list("deathgasp")
// If something forces the clown to fake death, it's pretty funny to still see the sad trombone played
trigger_causes = BIOCHIP_EMOTE_TRIGGER_UNINTENTIONAL | BIOCHIP_TRIGGER_DEATH_ANY
implant_data = /datum/implant_fluff/sad_trombone
implant_state = "implant-honk"
/obj/item/bio_chip/sad_trombone/emote_trigger(emote, mob/source, force)
activate(emote)
/obj/item/bio_chip/sad_trombone/death_trigger(mob/user, gibbed)
activate(gibbed)
/obj/item/bio_chip/sad_trombone/activate()
playsound(loc, 'sound/misc/sadtrombone.ogg', 50, FALSE)
/obj/item/bio_chip_implanter/sad_trombone
name = "bio-chip implanter (sad trombone)"
implant_type = /obj/item/bio_chip/sad_trombone
/obj/item/bio_chip_case/sad_trombone
name = "bio-chip case - 'Sad Trombone'"
desc = "A glass case containing a sad trombone bio-chip."
implant_type = /obj/item/bio_chip/sad_trombone
@@ -1,46 +0,0 @@
/obj/item/bio_chip/shock
name = "power bio-chip"
desc = "A shockingly effective bio-chip for stunning or killing all those in your way. Do it."
icon_state = "lighting_bolt"
item_color = "r"
origin_tech = "combat=5;magnets=3;biotech=4;syndicate=2"
implant_data = /datum/implant_fluff/shock
implant_state = "implant-syndicate"
var/enabled = FALSE
var/old_mclick_override
var/datum/middle_click_override/shock_implant/mclick_override = new /datum/middle_click_override/shock_implant
COOLDOWN_DECLARE(last_shocked)
var/shock_delay = 3 SECONDS
var/unlimited_power = FALSE // Does this really need explanation?
var/shock_range = 7
/obj/item/bio_chip/shock/activate()
enabled = !enabled
to_chat(imp_in, "<span class='notice'>You toggle the implant [enabled? "on" : "off"].</span>")
if(enabled)
if(imp_in.middleClickOverride)
old_mclick_override = imp_in.middleClickOverride
imp_in.middleClickOverride = mclick_override
else
if(old_mclick_override)
imp_in.middleClickOverride = old_mclick_override
old_mclick_override = null
else
imp_in.middleClickOverride = null
/obj/item/bio_chip/shock/removed()
if(old_mclick_override)
imp_in.middleClickOverride = old_mclick_override
old_mclick_override = null
else
imp_in.middleClickOverride = null
return ..()
/obj/item/bio_chip_implanter/shock
name = "bio-chip implanter (power)"
implant_type = /obj/item/bio_chip/shock
/obj/item/bio_chip_case/shock
name = "bio-chip case - 'power'"
desc = "A glass case containing a power bio-chip."
implant_type = /obj/item/bio_chip/shock
@@ -1,144 +0,0 @@
/**
* # Stealth Implant
*
* Implant which allows you to summon an MGS-style cardboard box that turns you invisble after a short delay.
*/
/obj/item/bio_chip/stealth
name = "S3 bio-chip"
desc = "Allows you to be hidden in plain sight."
implant_state = "implant-syndicate"
implant_data = /datum/implant_fluff/stealth
actions_types = list(/datum/action/item_action/agent_box)
/obj/item/bio_chip_implanter/stealth
name = "bio-chip implanter (stealth)"
implant_type = /obj/item/bio_chip/stealth
/datum/action/item_action/agent_box
name = "Deploy Box"
desc = "Find inner peace, here, in the box."
check_flags = AB_CHECK_HANDS_BLOCKED | AB_CHECK_IMMOBILE | AB_CHECK_CONSCIOUS | AB_CHECK_STUNNED
background_icon_state = "bg_agent"
button_icon_state = "deploy_box"
/// If TRUE, the box can't be deployed
var/on_cooldown = FALSE
/datum/action/item_action/agent_box/Trigger(trigger_flags, left_click)
. = ..()
if(!.)
return FALSE
if(istype(owner.loc, /obj/structure/closet/cardboard/agent))
var/obj/structure/closet/cardboard/agent/box = owner.loc
if(box.open())
owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
recall_box_animation()
return
// Box closing from here on out.
if(!isturf(owner.loc)) //Don't let the player use this to escape mechs/welded closets.
to_chat(owner, "<span class='warning'>You need more space to activate this implant!</span>")
return
owner.playsound_local(owner, 'sound/misc/box_deploy.ogg', 50, TRUE)
spawn_box()
/datum/action/item_action/agent_box/proc/spawn_box()
// Do the box's fade in spawn animation with an image so it follows the owner.
var/image/fake_box = image('icons/obj/cardboard_boxes.dmi', owner, "agentbox", ABOVE_MOB_LAYER)
flick_overlay_view(fake_box, owner, 0.4 SECONDS)
fake_box.alpha = 0
fake_box.pixel_z = 30
animate(fake_box, pixel_z = fake_box.pixel_z - 30, alpha = fake_box.alpha + 255, time = 3, loop = 1)
sleep(3)
// Spawn the actual box
var/obj/structure/closet/cardboard/agent/box = new(get_turf(owner), owner)
// Slightly shorter time since we needed 0.3s to to do the spawn animation.
INVOKE_ASYNC(box, TYPE_PROC_REF(/obj/structure/closet/cardboard/agent, go_invisible), 1.7 SECONDS)
owner.forceMove(box)
owner.overlay_fullscreen("agent_box", /atom/movable/screen/fullscreen/center/agent_box)
RegisterSignal(box, COMSIG_PARENT_QDELETING, PROC_REF(start_cooldown))
/datum/action/item_action/agent_box/proc/start_cooldown(datum/source)
SIGNAL_HANDLER
on_cooldown = TRUE
addtimer(CALLBACK(src, PROC_REF(end_cooldown)), 10 SECONDS)
owner.clear_fullscreen("agent_box")
build_all_button_icons()
/datum/action/item_action/agent_box/proc/end_cooldown()
on_cooldown = FALSE
build_all_button_icons()
/datum/action/item_action/agent_box/IsAvailable()
if(..() && !on_cooldown)
return TRUE
return FALSE
/datum/action/item_action/agent_box/proc/recall_box_animation()
var/image/fake_box = image('icons/obj/cardboard_boxes.dmi', owner, "agentbox", ABOVE_MOB_LAYER)
flick_overlay_view(fake_box, owner, 0.4 SECONDS)
animate(fake_box, pixel_z = fake_box.pixel_z + 30, alpha = fake_box.alpha - 255, time = 3, loop = 1)
/datum/action/item_action/agent_box/Grant(mob/grant_to)
. = ..()
if(owner)
RegisterSignal(owner, COMSIG_HUMAN_SUICIDE_ACT, PROC_REF(suicide_act))
/datum/action/item_action/agent_box/Remove(mob/M)
if(owner)
UnregisterSignal(owner, COMSIG_HUMAN_SUICIDE_ACT)
return ..()
/datum/action/item_action/agent_box/proc/suicide_act(datum/source)
SIGNAL_HANDLER
if(!istype(owner.loc, /obj/structure/closet/cardboard/agent))
return
var/obj/structure/closet/cardboard/agent/box = owner.loc
owner.visible_message("<span class='suicide'>[owner] falls out of [box]! It looks like [owner.p_they()] committed suicide!</span>")
owner.playsound_local(box, 'sound/misc/box_deploy.ogg', 50, TRUE)
INVOKE_ASYNC(box, TYPE_PROC_REF(/obj/structure/closet/cardboard/agent, open))
INVOKE_ASYNC(owner, TYPE_PROC_REF(/atom/movable, throw_at), get_turf(owner))
return OXYLOSS
// Stealth implant box
/obj/structure/closet/cardboard/agent
name = "inconspicious box"
desc = "It's so normal that you didn't notice it before."
icon_state = "agentbox"
max_integrity = 1
move_speed_multiplier = 0.5 // You can move at run speed while in this box.
material_drop = null
/obj/structure/closet/cardboard/agent/attackby__legacy__attackchain(obj/item/I, mob/living/user)
return
/obj/structure/closet/cardboard/agent/open()
. = ..()
if(!.)
return FALSE
qdel(src)
// When the box is opened, it's deleted, so we never need to update this.
/obj/structure/closet/cardboard/agent/update_icon_state()
return
/obj/structure/closet/cardboard/agent/proc/go_invisible(invis_time = 2 SECONDS)
animate(src, alpha = 0, time = invis_time)
sleep(invis_time)
// This is so people can't locate the box by spamming right click everywhere.
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
/obj/structure/closet/cardboard/agent/proc/reveal()
alpha = 255
mouse_opacity = MOUSE_OPACITY_OPAQUE
addtimer(CALLBACK(src, PROC_REF(go_invisible)), 1 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE)
/obj/structure/closet/cardboard/agent/Bump(atom/A)
. = ..()
if(isliving(A))
reveal()
/obj/structure/closet/cardboard/agent/Bumped(atom/movable/A)
. = ..()
if(isliving(A))
reveal()
@@ -1,74 +0,0 @@
/obj/item/storage/hidden_implant
name = "bluespace pocket"
storage_slots = 2
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = WEIGHT_CLASS_GIGANTIC
w_class = WEIGHT_CLASS_BULKY
cant_hold = list(/obj/item/disk/nuclear)
w_class_override = list(/obj/item/storage/belt)
silent = TRUE
/obj/item/bio_chip/storage
name = "storage bio-chip"
desc = "Stores up to two big items in a bluespace pocket."
icon_state = "storage"
origin_tech = "materials=2;magnets=4;bluespace=5;syndicate=4"
item_color = "r"
implant_data = /datum/implant_fluff/storage
implant_state = "implant-syndicate"
var/obj/item/storage/hidden_implant/storage
/obj/item/bio_chip/storage/Initialize(mapload)
. = ..()
storage = new /obj/item/storage/hidden_implant(src)
/obj/item/bio_chip/storage/emp_act(severity)
..()
storage.emp_act(severity)
/obj/item/bio_chip/storage/activate()
if(!length(storage.mobs_viewing))
storage.MouseDrop(imp_in)
else
for(var/mob/to_close in storage.mobs_viewing)
storage.close(to_close)
/obj/item/bio_chip/storage/removed(source)
if(..())
for(var/mob/M in range(1))
if(M.s_active == storage)
storage.close(M)
for(var/obj/item/I in storage)
storage.remove_from_storage(I, get_turf(source))
return TRUE
/obj/item/bio_chip/storage/implant(mob/source)
var/obj/item/bio_chip/storage/imp_e = locate(type) in source
if(imp_e)
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
for(var/mob/M in range(1))
if(M.s_active == storage)
storage.close(M)
storage.show_to(source)
qdel(src)
return TRUE
return ..()
/obj/item/bio_chip/storage/proc/get_contents() //Used for swiftly returning a list of the implant's contents i.e. for checking a theft objective's completion.
if(storage && storage.contents)
return storage.contents
/obj/item/bio_chip_implanter/storage
name = "bio-chip implanter (storage)"
implant_type = /obj/item/bio_chip/storage
/obj/item/bio_chip_case/storage
name = "bio-chip case - 'Storage'"
desc = "A glass case containing a storage bio-chip."
implant_type = /obj/item/bio_chip/storage
@@ -1,34 +0,0 @@
/obj/item/bio_chip/supercharge
name = "supercharge bio-chip"
desc = "Removes all stuns and knockdowns."
icon_state = "adrenal"
origin_tech = "materials=3;combat=5;syndicate=4"
uses = 3
implant_data = /datum/implant_fluff/adrenaline
implant_state = "implant-syndicate"
/obj/item/bio_chip/supercharge/activate()
uses--
to_chat(imp_in, "<span class='notice'>You feel an electric sensation as your components enter overdrive!</span>")
imp_in.SetStunned(0)
imp_in.SetWeakened(0)
imp_in.SetKnockDown(0)
imp_in.SetParalysis(0)
imp_in.adjustStaminaLoss(-75)
imp_in.stand_up(TRUE)
SEND_SIGNAL(imp_in, COMSIG_LIVING_CLEAR_STUNS)
imp_in.reagents.add_reagent("recal", 10)
imp_in.reagents.add_reagent("surge_plus", 10)
imp_in.reagents.add_reagent("synthetic_omnizine_no_addiction", 10)
if(!uses)
qdel(src)
/obj/item/bio_chip_implanter/supercharge
name = "bio-chip implanter (supercharge)"
implant_type = /obj/item/bio_chip/supercharge
/obj/item/bio_chip_case/supercharge
name = "bio-chip case - 'supercharge'"
desc = "A glass case containing a supercharge bio-chip."
implant_type = /obj/item/bio_chip/supercharge
@@ -1,52 +0,0 @@
/obj/item/bio_chip/tracking
name = "tracking bio-chip"
desc = "Track with this."
activated = BIOCHIP_ACTIVATED_PASSIVE
origin_tech = "materials=2;magnets=2;programming=2;biotech=2"
implant_data = /datum/implant_fluff/tracking
implant_state = "implant-nanotrasen"
var/warn_cooldown = 0
var/obj/item/gps/internal_gps
var/gpstag = "TRACK0"
var/internal_gps_path = /obj/item/gps/internal/tracking_implant
/obj/item/bio_chip/tracking/Initialize(mapload)
. = ..()
GLOB.tracked_implants += src
/obj/item/bio_chip/tracking/Destroy()
QDEL_NULL(internal_gps)
GLOB.tracked_implants -= src
return ..()
/obj/item/bio_chip/tracking/implant(mob/target)
if(ishuman(target))
var/mob/living/carbon/human/H = target
var/obj/item/organ/internal/cyberimp/chest/bluespace_anchor/anchor = H.get_int_organ(/obj/item/organ/internal/cyberimp/chest/bluespace_anchor)
if(anchor)
target.visible_message("<span class='danger'>[src] sparks out, disrupted by [anchor] inside [H]!</span>")
qdel(src)
return FALSE
. = ..()
if(!.)
return
internal_gps = new internal_gps_path(src)
if(gpstag)
internal_gps.gpstag = gpstag
/obj/item/bio_chip/tracking/removed(mob/target)
. = ..()
if(.)
QDEL_NULL(internal_gps)
/obj/item/gps/internal/tracking_implant
local = FALSE
/obj/item/bio_chip_implanter/tracking
name = "bio-chip implanter (tracking)"
implant_type = /obj/item/bio_chip/tracking
/obj/item/bio_chip_case/tracking
name = "bio-chip case - 'Tracking'"
desc = "A glass case containing a tracking bio-chip."
implant_type = /obj/item/bio_chip/tracking
@@ -1,55 +0,0 @@
/obj/item/bio_chip/traitor
name = "Mindslave Bio-chip"
desc = "Divide and Conquer!"
origin_tech = "programming=5;biotech=5;syndicate=8"
activated = FALSE
implant_data = /datum/implant_fluff/traitor
implant_state = "implant-syndicate"
/// The UID of the mindslave's `mind`. Stored to solve GC race conditions and ensure we can remove their mindslave status even when they're deleted or gibbed.
var/mindslave_UID
/obj/item/bio_chip/traitor/implant(mob/living/carbon/human/mindslave_target, mob/living/carbon/human/user)
// Check `activated` here so you can't just keep taking it out and putting it back into other people.
if(activated || !istype(mindslave_target) || !istype(user)) // Both the target and the user need to be human.
return FALSE
// If the target is catatonic or doesn't have a mind, return.
if(!mindslave_target.mind)
to_chat(user, "<span class='warning'><i>This person doesn't have a mind for you to slave!</i></span>")
return FALSE
// Fails if they're already a mindslave of someone, or if they're mindshielded.
if(IS_MINDSLAVE(mindslave_target) || ismindshielded(mindslave_target))
mindslave_target.visible_message(
"<span class='warning'>[mindslave_target] seems to resist the bio-chip!</span>", \
"<span class='warning'>You feel a strange sensation in your head that quickly dissipates.</span>")
qdel(src)
return FALSE
// Mindslaving yourself.
if(mindslave_target == user)
to_chat(user, "<span class='notice'>Making yourself loyal to yourself was a great idea! Perhaps even the best idea ever! Actually, you just feel like an idiot.</span>")
user.adjustBrainLoss(20)
qdel(src)
return FALSE
// Create a new mindslave datum for the target with the user as their master.
mindslave_target.mind.add_antag_datum(new /datum/antagonist/mindslave/implant(user.mind))
mindslave_UID = mindslave_target.mind.UID()
log_admin("[key_name_admin(user)] has mind-slaved [key_name_admin(mindslave_target)].")
return ..()
/obj/item/bio_chip/traitor/removed(mob/target)
. = ..()
var/datum/mind/M = locateUID(mindslave_UID)
M.remove_antag_datum(/datum/antagonist/mindslave/implant)
/obj/item/bio_chip_implanter/traitor
name = "bio-chip implanter (Mindslave)"
implant_type = /obj/item/bio_chip/traitor
/obj/item/bio_chip_case/traitor
name = "bio-chip case - 'Mindslave'"
desc = "A glass case containing a mindslave bio-chip."
implant_type = /obj/item/bio_chip/traitor
@@ -1,62 +0,0 @@
/obj/item/bio_chip/uplink
name = "uplink bio-chip"
desc = "Summon things."
icon = 'icons/obj/radio.dmi'
icon_state = "radio"
origin_tech = "materials=4;magnets=4;programming=4;biotech=4;syndicate=5;bluespace=5"
implant_data = /datum/implant_fluff/uplink
implant_state = "implant-syndicate"
/obj/item/bio_chip/uplink/Initialize(mapload)
. = ..()
hidden_uplink = new(src)
hidden_uplink.uses = 50
/obj/item/bio_chip/uplink/nuclear/Initialize(mapload)
. = ..()
if(hidden_uplink)
hidden_uplink.update_uplink_type(UPLINK_TYPE_NUCLEAR)
/obj/item/bio_chip/uplink/sit/Initialize(mapload)
. = ..()
if(hidden_uplink)
hidden_uplink.update_uplink_type(UPLINK_TYPE_SIT)
/obj/item/bio_chip/uplink/admin/Initialize(mapload)
. = ..()
if(hidden_uplink)
hidden_uplink.update_uplink_type(UPLINK_TYPE_ADMIN)
/obj/item/bio_chip/uplink/implant(mob/source)
var/obj/item/bio_chip/imp_e = locate(type) in source
if(imp_e && imp_e != src)
imp_e.hidden_uplink.uses += hidden_uplink.uses
qdel(src)
return TRUE
if(..())
hidden_uplink.uplink_owner="[source.key]"
return TRUE
return FALSE
/obj/item/bio_chip/uplink/activate()
if(hidden_uplink)
hidden_uplink.check_trigger(imp_in)
/obj/item/bio_chip_implanter/uplink
name = "bio-chip implanter (uplink)"
implant_type = /obj/item/bio_chip/uplink
/obj/item/bio_chip_case/uplink
name = "bio-chip case - 'Syndicate Uplink'"
desc = "A glass case containing an uplink bio-chip."
implant_type = /obj/item/bio_chip/uplink
/obj/item/bio_chip_implanter/nuclear
name = "bio-chip implanter (Nuclear Agent Uplink)"
implant_type = /obj/item/bio_chip/uplink/nuclear
/obj/item/bio_chip_case/nuclear
name = "bio-chip case - 'Nuclear Agent Uplink'"
implant_type = /obj/item/bio_chip/uplink/nuclear
@@ -1,55 +0,0 @@
/obj/item/bio_chip_implanter
name = "bio-chip implanter"
desc = "A sterile automatic bio-chip injector."
icon = 'icons/obj/bio_chips.dmi'
icon_state = "implanter0"
item_state = "syringe_0"
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
origin_tech = "materials=2;biotech=3"
materials = list(MAT_METAL = 600, MAT_GLASS = 200)
var/obj/item/bio_chip/imp
var/obj/item/bio_chip/implant_type
/obj/item/bio_chip_implanter/update_icon_state()
if(imp)
icon_state = "implanter1"
origin_tech = imp.origin_tech
else
icon_state = "implanter0"
origin_tech = initial(origin_tech)
/obj/item/bio_chip_implanter/attack__legacy__attackchain(mob/living/carbon/M, mob/user)
if(!iscarbon(M))
return
if(user && imp)
if(M != user)
M.visible_message("<span class='warning'>[user] is attempting to bio-chip [M].</span>")
var/turf/T = get_turf(M)
if(T && (M == user || do_after(user, 50 * toolspeed, target = M)))
if(user && M && (get_turf(M) == T) && src && imp)
if(imp.implant(M, user))
if(M == user)
to_chat(user, "<span class='notice'>You bio-chip yourself.</span>")
else
M.visible_message("[user] has implanted [M].", "<span class='notice'>[user] bio-chips you.</span>")
imp = null
update_icon(UPDATE_ICON_STATE)
/obj/item/bio_chip_implanter/attackby__legacy__attackchain(obj/item/W, mob/user, params)
..()
if(is_pen(W))
rename_interactive(user, W)
/obj/item/bio_chip_implanter/Initialize(mapload)
. = ..()
if(!implant_type)
return
imp = new implant_type()
update_icon(UPDATE_ICON_STATE)
/obj/item/bio_chip_implanter/Destroy()
QDEL_NULL(imp)
. = ..()
@@ -1,991 +0,0 @@
/* Cards
* Contains:
* DATA CARD
* ID CARD
* FINGERPRINT CARD HOLDER
* FINGERPRINT CARD
*/
/obj/item/card
name = "card"
desc = "A card."
icon = 'icons/obj/card.dmi'
w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_ID
new_attack_chain = TRUE
var/associated_account_number = 0
var/list/files = list()
/obj/item/card/proc/get_card_account()
return GLOB.station_money_database.find_user_account(associated_account_number)
/*
* ID CARDS
*/
/obj/item/card/emag_broken
desc = "It's a card with a magnetic strip attached to some circuitry. It looks too busted to be used for anything but salvage."
name = "broken cryptographic sequencer"
icon_state = "emag"
item_state = "card-id"
origin_tech = "magnets=2;syndicate=2"
prefered_slot_flags = ITEM_SLOT_BOTH_POCKETS
/obj/item/card/emag
desc = "It's a card with a magnetic strip attached to some circuitry."
name = "cryptographic sequencer"
icon_state = "emag"
item_state = "card-id"
origin_tech = "magnets=2;syndicate=2"
flags = NOBLUDGEON
flags_2 = NO_MAT_REDEMPTION_2
prefered_slot_flags = ITEM_SLOT_BOTH_POCKETS
/obj/item/card/emag/pre_attack(atom/target, mob/living/user, params)
if(..() || ismob(target))
return FINISH_ATTACK
/obj/item/card/emag/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(target.emag_act(user))
return ITEM_INTERACT_COMPLETE
/obj/item/card/emag/magic_key
name = "magic key"
desc = "It's a magic key, that will open one door!"
icon_state = "magic_key"
origin_tech = "magnets=2"
/obj/item/card/emag/magic_key/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!isairlock(target))
return NONE
var/obj/machinery/door/D = target
D.locked = FALSE
D.update_icon()
D.emag_act(user)
qdel(src)
return ITEM_INTERACT_COMPLETE
/obj/item/card/cmag
desc = "It's a card coated in a slurry of electromagnetic bananium."
name = "jestographic sequencer"
icon_state = "cmag"
item_state = "card-id"
origin_tech = "magnets=2;syndicate=2"
flags = NOBLUDGEON
flags_2 = NO_MAT_REDEMPTION_2
prefered_slot_flags = ITEM_SLOT_BOTH_POCKETS
/obj/item/card/cmag/Initialize(mapload)
. = ..()
AddComponent(/datum/component/slippery, src, 16 SECONDS, 100)
/obj/item/card/cmag/pre_attack(atom/target, mob/living/user, params)
if(..() || ismob(target))
return FINISH_ATTACK
/obj/item/card/cmag/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(target.cmag_act(user))
return ITEM_INTERACT_COMPLETE
/obj/item/card/id
name = "identification card"
desc = "A card used to provide ID and determine access across the station."
icon_state = "id"
item_state = "card-id"
/// For redeeming at mining equipment lockers
var/mining_points = 0
/// Total mining points for the Shift.
var/total_mining_points = 0
var/list/access = list()
var/registered_name = "Unknown" // The name registered_name on the card
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 100)
resistance_flags = FIRE_PROOF | ACID_PROOF
var/untrackable // Can not be tracked by AI's
var/blood_type = "\[UNSET\]"
var/dna_hash = "\[UNSET\]"
var/fingerprint_hash = "\[UNSET\]"
//alt titles are handled a bit weirdly in order to unobtrusively integrate into existing ID system
var/assignment = null //can be alt title or the actual job
var/rank = null //actual job
var/owner_uid
var/owner_ckey
var/lastlog
var/dorm = 0 // determines if this ID has claimed a dorm already
var/sex
var/age
var/photo
var/dat
var/stamped = 0
/// Can we flash the ID?
var/can_id_flash = TRUE
var/obj/item/card/id/guest/guest_pass = null // Guest pass attached to the ID
/obj/item/card/id/New()
..()
spawn(30)
if(ishuman(loc) && blood_type == "\[UNSET\]")
var/mob/living/carbon/human/H = loc
SetOwnerInfo(H)
/obj/item/card/id/examine(mob/user)
. = ..()
if(in_range(user, src))
show(usr)
else
. += "<span class='warning'>It is too far away.</span>"
if(guest_pass)
. += "<span class='notice'>There is a guest pass attached to this ID card, <b>Alt-Click</b> to remove it.</span>"
if(world.time < guest_pass.expiration_time)
. += "<span class='notice'>It expires at [station_time_timestamp("hh:mm:ss", guest_pass.expiration_time)].</span>"
else
. += "<span class='warning'>It expired at [station_time_timestamp("hh:mm:ss", guest_pass.expiration_time)].</span>"
. += "<span class='notice'>It grants access to following areas:</span>"
for(var/A in guest_pass.temp_access)
. += "<span class='notice'>[get_access_desc(A)].</span>"
. += "<span class='notice'>Issuing reason: [guest_pass.reason].</span>"
/obj/item/card/id/proc/show(mob/user as mob)
var/datum/asset/assets = get_asset_datum(/datum/asset/simple/paper)
assets.send(user)
var/datum/browser/popup = new(user, "idcard", name, 600, 400)
popup.set_content(dat)
popup.open()
/obj/item/card/id/activate_self(mob/user)
if(..())
return
if(can_id_flash)
flash_card(user)
/obj/item/card/id/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!isliving(target))
return NONE
return shared_interact(target, user)
/obj/item/card/id/ranged_interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(isliving(target) && get_dist(target, user) <= 2)
return shared_interact(target, user)
return NONE
/obj/item/card/id/proc/shared_interact(mob/living/victim, mob/living/user)
if(victim.has_status_effect(STATUS_EFFECT_OFFERING_EFTPOS))
var/obj/item/eftpos/eftpos = victim.is_holding_item_of_type(/obj/item/eftpos)
if(!eftpos || !eftpos.can_offer)
to_chat(user, "<span class='warning'>They don't seem to have it in hand anymore.</span>")
return ITEM_INTERACT_COMPLETE
victim.remove_status_effect(STATUS_EFFECT_OFFERING_EFTPOS)
eftpos.scan_card(src, user)
return ITEM_INTERACT_COMPLETE
return NONE
/obj/item/card/id/proc/UpdateName()
name = "[registered_name]'s ID Card ([assignment])"
/obj/item/card/id/proc/SetOwnerInfo(mob/living/carbon/human/H)
if(!H || !H.dna)
return
sex = capitalize(H.gender)
age = H.age
blood_type = H.dna.blood_type
dna_hash = H.dna.unique_enzymes
fingerprint_hash = md5(H.dna.uni_identity)
RebuildHTML()
/obj/item/card/id/proc/RebuildHTML()
var/photo_front = "'data:image/png;base64,[icon2base64(icon(photo, dir = SOUTH))]'"
var/photo_side = "'data:image/png;base64,[icon2base64(icon(photo, dir = WEST))]'"
dat = {"<table><tr><td>
Name: [registered_name]</A><BR>
Sex: [sex]</A><BR>
Age: [age]</A><BR>
Rank: [assignment]</A><BR>
Fingerprint: [fingerprint_hash]</A><BR>
Blood Type: [blood_type]<BR>
DNA Hash: [dna_hash]<BR><BR>
<td align = center valign = top>Photo:<br><img src=[photo_front] height=80 width=80 border=4>
<img src=[photo_side] height=80 width=80 border=4></td></tr></table>"}
/obj/item/card/id/GetAccess()
if(!guest_pass)
return access
return access | guest_pass.GetAccess()
/obj/item/card/id/proc/attach_guest_pass(obj/item/card/id/guest/G, mob/user)
if(world.time > G.expiration_time)
to_chat(user, "There's no point, the guest pass has expired.")
return
if(guest_pass)
to_chat(user, "There's already a guest pass attached to this ID.")
return
if(G.registered_name != registered_name && G.registered_name != "NOT SPECIFIED")
to_chat(user, "The guest pass cannot be attached to this ID.")
return
if(!user.transfer_item_to(G, src))
return
guest_pass = G
/obj/item/card/id/GetID()
return src
/obj/item/card/id/proc/getRankAndAssignment()
var/jobnamedata = ""
if(rank)
jobnamedata += rank
if(rank != assignment)
jobnamedata += " (" + assignment + ")"
return jobnamedata
/obj/item/card/id/proc/getPlayer()
if(owner_uid)
var/mob/living/carbon/human/H = locateUID(owner_uid)
if(istype(H) && H.ckey == owner_ckey)
return H
owner_uid = null
if(owner_ckey)
for(var/mob/M in GLOB.player_list)
if(M.ckey && M.ckey == owner_ckey)
owner_uid = M.UID()
return M
owner_ckey = null
/obj/item/card/id/proc/getPlayerCkey()
var/mob/living/carbon/human/H = getPlayer()
if(istype(H))
return H.ckey
/obj/item/card/id/proc/is_untrackable()
return untrackable
/obj/item/card/id/proc/update_label(newname, newjob)
if(newname || newjob)
name = "[(!newname) ? "identification card" : "[newname]'s ID Card"][(!newjob) ? "" : " ([newjob])"]"
return
name = "[(!registered_name) ? "identification card" : "[registered_name]'s ID Card"][(!assignment) ? "" : " ([assignment])"]"
/obj/item/card/id/proc/get_departments()
return get_departments_from_job(rank)
/obj/item/card/id/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(istype(used, /obj/item/id_decal/))
var/obj/item/id_decal/decal = used
to_chat(user, "You apply [decal] to [src].")
if(decal.override_name)
name = decal.decal_name
desc = decal.decal_desc
icon_state = decal.decal_icon_state
item_state = decal.decal_item_state
qdel(decal)
qdel(used)
return ITEM_INTERACT_COMPLETE
else if(istype(used, /obj/item/barcodescanner))
var/obj/item/barcodescanner/B = used
B.scanID(src, user)
return ITEM_INTERACT_COMPLETE
else if(istype(used, /obj/item/stamp))
if(!stamped)
dat+="<img src=large_[used.icon_state].png>"
stamped = 1
to_chat(user, "You stamp the ID card!")
playsound(user, 'sound/items/handling/standard_stamp.ogg', 50, vary = TRUE)
return ITEM_INTERACT_COMPLETE
to_chat(user, "This ID has already been stamped!")
return ITEM_INTERACT_COMPLETE
else if(istype(used, /obj/item/card/id/guest))
attach_guest_pass(used, user)
return ITEM_INTERACT_COMPLETE
else if(istype(used, /obj/item/storage/wallet))
used.attackby__legacy__attackchain(src, user)
return ITEM_INTERACT_COMPLETE
/obj/item/card/id/AltClick(mob/user)
if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user))
return
if(guest_pass)
to_chat(user, "<span class='notice'>You remove the guest pass from this ID.</span>")
guest_pass.forceMove(get_turf(src))
guest_pass = null
else
to_chat(user, "<span class='warning'>There is no guest pass attached to this ID.</span>")
/obj/item/card/id/serialize()
var/list/data = ..()
data["sex"] = sex
data["age"] = age
data["btype"] = blood_type
data["dna_hash"] = dna_hash
data["fprint_hash"] = fingerprint_hash
data["access"] = access
data["assignment"] = assignment
data["rank"] = rank
data["account"] = associated_account_number
data["owner"] = registered_name
data["mining"] = mining_points
data["total_mining"] = total_mining_points
return data
/obj/item/card/id/deserialize(list/data)
sex = data["sex"]
age = data["age"]
blood_type = data["btype"]
dna_hash = data["dna_hash"]
fingerprint_hash = data["fprint_hash"]
access = data["access"] // No need for a copy, the list isn't getting touched
assignment = data["job"] // backup for old jsons
assignment = data["assignment"]
rank = data["rank"]
associated_account_number = data["account"]
registered_name = data["owner"]
mining_points = data["mining"]
total_mining_points = data["total_mining"]
// We'd need to use icon serialization(b64) to save the photo, and I don't feel like i
UpdateName()
RebuildHTML()
..()
/obj/item/card/id/proc/flash_card(mob/user)
user.visible_message("[user] shows you: [bicon(src)] [name]. The assignment on the card: [assignment]",\
"You flash your ID card: [bicon(src)] [name]. The assignment on the card: [assignment]")
if(mining_points)
to_chat(user, "There's <b>[mining_points] Mining Points</b> loaded onto this card. This card has earned <b>[total_mining_points] Mining Points</b> this Shift!")
add_fingerprint(user)
/obj/item/card/id/silver
desc = "A silver card which shows honour and dedication."
icon_state = "silver"
item_state = "silver_id"
/obj/item/card/id/gold
desc = "A golden card which shows power and might."
icon_state = "gold"
item_state = "gold_id"
/obj/item/card/id/captains_spare
name = "captain's spare ID"
desc = "The spare ID of the captain. Keep this secured."
icon_state = "gold"
item_state = "gold_id"
registered_name = "Captain"
assignment = "Captain"
/obj/item/card/id/captains_spare/New()
access = get_all_accesses()
..()
/obj/item/card/id/admin
name = "admin ID card"
icon_state = "admin"
item_state = "gold_id"
registered_name = "Admin"
assignment = "Testing Shit"
untrackable = TRUE
/obj/item/card/id/admin/New()
access = get_absolutely_all_accesses()
..()
/obj/item/card/id/centcom
name = "central command ID card"
desc = "An ID straight from Central Command."
icon_state = "centcom"
registered_name = "Central Command"
assignment = "General"
/obj/item/card/id/centcom/New()
access = get_all_centcom_access()
..()
/obj/item/card/id/prisoner
name = "prisoner ID card"
desc = "You are a number, you are not a free man."
icon_state = "prisoner"
item_state = "orange-id"
assignment = "Prisoner"
registered_name = "Scum"
access = list(ACCESS_LIBRARY)
/// How many mining points you need to be released from the labour camp.
var/goal = 0
/obj/item/card/id/prisoner/examine(mob/user)
. = ..()
if(goal)
. += "\nYou have accumulated [mining_points] out of the [goal] points assigned to gain freedom."
/obj/item/card/id/prisoner/one
name = "Prisoner #13-001"
icon_state = "prisonerone"
registered_name = "Prisoner #13-001"
/obj/item/card/id/prisoner/two
name = "Prisoner #13-002"
icon_state = "prisonertwo"
registered_name = "Prisoner #13-002"
/obj/item/card/id/prisoner/three
name = "Prisoner #13-003"
icon_state = "prisonerthree"
registered_name = "Prisoner #13-003"
/obj/item/card/id/prisoner/four
name = "Prisoner #13-004"
icon_state = "prisonerfour"
registered_name = "Prisoner #13-004"
/obj/item/card/id/prisoner/five
name = "Prisoner #13-005"
icon_state = "prisonerfive"
registered_name = "Prisoner #13-005"
/obj/item/card/id/prisoner/six
name = "Prisoner #13-006"
icon_state = "prisonersix"
registered_name = "Prisoner #13-006"
/obj/item/card/id/prisoner/seven
name = "Prisoner #13-007"
icon_state = "prisonerseven"
registered_name = "Prisoner #13-007"
/obj/item/card/id/prisoner/random
/obj/item/card/id/prisoner/random/New()
..()
var/random_number = "#[rand(0, 99)]-[rand(0, 999)]"
name = "Prisoner [random_number]"
registered_name = name
/obj/item/card/id/medical
name = "Medical ID"
registered_name = "Medic"
icon_state = "medical"
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/coroner
name = "Coroner ID"
registered_name = "Coroner"
icon_state = "coroner"
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/virologist
name = "Virologist ID"
registered_name = "Virologist"
icon_state = "virologist"
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS)
/obj/item/card/id/chemist
name = "Chemist ID"
registered_name = "Chemist"
icon_state = "chemist"
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/paramedic
name = "Paramedic ID"
registered_name = "Paramedic"
icon_state = "paramedic"
access = list(ACCESS_PARAMEDIC, ACCESS_MEDICAL, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_MORGUE)
/obj/item/card/id/psychiatrist
name = "Psychiatrist ID"
registered_name = "Psychiatrist"
icon_state = "psychiatrist"
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_PSYCHIATRIST)
/obj/item/card/id/security
name = "Security ID"
registered_name = "Officer"
icon_state = "security"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_EVIDENCE, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS)
/obj/item/card/id/detective
name = "Detective ID"
registered_name = "Detective"
icon_state = "detective"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_EVIDENCE, ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_COURT, ACCESS_WEAPONS)
/obj/item/card/id/warden
name = "Warden ID"
registered_name = "Warden"
icon_state = "warden"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_EVIDENCE, ACCESS_ARMORY, ACCESS_COURT, ACCESS_MAINT_TUNNELS, ACCESS_MORGUE, ACCESS_WEAPONS)
/obj/item/card/id/internalaffairsagent
name = "Internal Affairs Agent ID"
registered_name = "Internal Affairs Agent"
icon_state = "internalaffairsagent"
access = list(ACCESS_INTERNAL_AFFAIRS, ACCESS_COURT, ACCESS_SEC_DOORS, ACCESS_MAINT_TUNNELS, ACCESS_RESEARCH, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING)
/obj/item/card/id/geneticist
name = "Geneticist ID"
registered_name = "Geneticist"
icon_state = "geneticist"
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_SURGERY, ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_GENETICS, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/research
name = "Research ID"
registered_name = "Scientist"
icon_state = "research"
access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/xenobiology
name = "Xenobiology ID"
registered_name = "Xenobiologist"
icon_state = "xenobiologist"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM, ACCESS_RESEARCH, ACCESS_XENOBIOLOGY, ACCESS_EVA, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_TELEPORTER)
/obj/item/card/id/roboticist
name = "Roboticist ID"
registered_name = "Roboticist"
icon_state = "roboticist"
access = list(ACCESS_ROBOTICS, ACCESS_TOX, ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_MORGUE, ACCESS_RESEARCH, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/supply
name = "Supply ID"
registered_name = "Cargonian"
icon_state = "cargo"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/smith
name = "Smith ID"
registered_name = "Smith"
icon_state = "smith"
access = list(ACCESS_CARGO_BAY, ACCESS_CARGO, ACCESS_MAINT_TUNNELS, ACCESS_MINERAL_STOREROOM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_SMITH)
/obj/item/card/id/quartermaster
name = "Quartermaster ID"
registered_name = "Quartermaster"
icon_state = "quartermaster"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM, ACCESS_SMITH)
/obj/item/card/id/shaftminer
name = "Shaftminer ID"
registered_name = "Shaftminer"
icon_state = "shaftminer"
access = list(ACCESS_MAINT_TUNNELS, ACCESS_MAILSORTING, ACCESS_CARGO, ACCESS_QM, ACCESS_MINING, ACCESS_MINING_STATION, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/engineering
name = "Engineering ID"
registered_name = "Engineer"
icon_state = "engineering"
access = list(ACCESS_EVA, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS)
/obj/item/card/id/atmostech
name = "Life Support Specialist ID"
registered_name = "Life Support Specialist"
icon_state = "atmostech"
access = list(ACCESS_EVA, ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_CONSTRUCTION, ACCESS_ATMOSPHERICS)
/obj/item/card/id/captains_spare/assigned
name = "Captain ID"
icon_state = "captain"
/obj/item/card/id/hop
name = "Head of Personal ID"
registered_name = "HoP"
icon_state = "HoP"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS,
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_AI_UPLOAD, ACCESS_EVA, ACCESS_HEADS,
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_INTERNAL_AFFAIRS,
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_HEADS_VAULT, ACCESS_MINING_STATION,
ACCESS_CLOWN, ACCESS_MIME, ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_EXPEDITION, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/hos
name = "Head of Security ID"
registered_name = "HoS"
icon_state = "HoS"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_EVIDENCE, ACCESS_ARMORY, ACCESS_COURT,
ACCESS_FORENSICS_LOCKERS, ACCESS_MORGUE, ACCESS_MAINT_TUNNELS, ACCESS_ALL_PERSONAL_LOCKERS,
ACCESS_RESEARCH, ACCESS_ENGINE, ACCESS_MINING, ACCESS_MEDICAL, ACCESS_CONSTRUCTION, ACCESS_MAILSORTING,
ACCESS_HEADS, ACCESS_HOS, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_EXPEDITION, ACCESS_WEAPONS)
/obj/item/card/id/cmo
name = "Chief Medical Officer ID"
registered_name = "CMO"
icon_state = "CMO"
access = list(ACCESS_MEDICAL, ACCESS_MORGUE, ACCESS_GENETICS, ACCESS_HEADS,
ACCESS_CHEMISTRY, ACCESS_VIROLOGY, ACCESS_CMO, ACCESS_SURGERY, ACCESS_RC_ANNOUNCE,
ACCESS_KEYCARD_AUTH, ACCESS_SEC_DOORS, ACCESS_PSYCHIATRIST, ACCESS_PARAMEDIC, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/rd
name = "Research Director ID"
registered_name = "RD"
icon_state = "RD"
access = list(ACCESS_RD, ACCESS_HEADS, ACCESS_TOX, ACCESS_GENETICS, ACCESS_MORGUE,
ACCESS_TOX_STORAGE, ACCESS_TECH_STORAGE, ACCESS_TELEPORTER, ACCESS_SEC_DOORS,
ACCESS_RESEARCH, ACCESS_ROBOTICS, ACCESS_XENOBIOLOGY, ACCESS_AI_UPLOAD,
ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_EXPEDITION, ACCESS_MINISAT, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/ce
name = "Chief Engineer ID"
registered_name = "CE"
icon_state = "CE"
access = list(ACCESS_ENGINE, ACCESS_ENGINE_EQUIP, ACCESS_TECH_STORAGE, ACCESS_MAINT_TUNNELS,
ACCESS_TELEPORTER, ACCESS_EXTERNAL_AIRLOCKS, ACCESS_ATMOSPHERICS, ACCESS_EVA,
ACCESS_HEADS, ACCESS_CONSTRUCTION, ACCESS_SEC_DOORS,
ACCESS_CE, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_TCOMSAT, ACCESS_MINISAT, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/ntrep
name = "Nanotrasen Representative ID"
registered_name = "NTRep"
icon_state = "ntrep"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS,
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_CHANGE_IDS, ACCESS_EVA, ACCESS_HEADS,
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_INTERNAL_AFFAIRS,
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_HEADS_VAULT, ACCESS_MINING_STATION,
ACCESS_CLOWN, ACCESS_MIME, ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_EXPEDITION, ACCESS_WEAPONS, ACCESS_NTREP)
/obj/item/card/id/nct
name = "\improper Nanotrasen Career Trainer ID"
registered_name = "Nanotrasen Career Trainer"
icon_state = "nctrainer"
access = list(ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_CARGO, ACCESS_CONSTRUCTION, ACCESS_COURT, ACCESS_EVA, ACCESS_TRAINER, ACCESS_MAINT_TUNNELS,
ACCESS_MEDICAL, ACCESS_RESEARCH, ACCESS_SEC_DOORS, ACCESS_THEATRE, ACCESS_INTERNAL_AFFAIRS)
/obj/item/card/id/blueshield
name = "Blueshield ID"
registered_name = "Blueshield"
icon_state = "blueshield"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS,
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_EVIDENCE, ACCESS_CHANGE_IDS, ACCESS_EVA, ACCESS_HEADS,
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_INTERNAL_AFFAIRS,
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_HEADS_VAULT, ACCESS_MINING_STATION,
ACCESS_CLOWN, ACCESS_MIME, ACCESS_HOP, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_EXPEDITION, ACCESS_WEAPONS, ACCESS_BLUESHIELD)
/obj/item/card/id/magistrate
name = "Magistrate ID"
registered_name = "Magistrate"
icon_state = "magistrate"
access = list(ACCESS_SECURITY, ACCESS_SEC_DOORS, ACCESS_BRIG, ACCESS_COURT, ACCESS_FORENSICS_LOCKERS,
ACCESS_MEDICAL, ACCESS_ENGINE, ACCESS_EVIDENCE, ACCESS_CHANGE_IDS, ACCESS_EVA, ACCESS_HEADS,
ACCESS_ALL_PERSONAL_LOCKERS, ACCESS_MAINT_TUNNELS, ACCESS_BAR, ACCESS_JANITOR, ACCESS_CONSTRUCTION, ACCESS_MORGUE,
ACCESS_CREMATORIUM, ACCESS_KITCHEN, ACCESS_CARGO, ACCESS_CARGO_BOT, ACCESS_MAILSORTING, ACCESS_QM, ACCESS_HYDROPONICS, ACCESS_INTERNAL_AFFAIRS,
ACCESS_THEATRE, ACCESS_CHAPEL_OFFICE, ACCESS_LIBRARY, ACCESS_RESEARCH, ACCESS_MINING, ACCESS_HEADS_VAULT, ACCESS_MINING_STATION,
ACCESS_CLOWN, ACCESS_MIME, ACCESS_RC_ANNOUNCE, ACCESS_KEYCARD_AUTH, ACCESS_EXPEDITION, ACCESS_MAGISTRATE)
/obj/item/card/id/assistant
name = "Assistant ID"
registered_name = "Assistant"
icon_state = "assistant"
access = list(ACCESS_MAINT_TUNNELS)
/obj/item/card/id/clown
name = "Pink ID"
registered_name = "HONK!"
icon_state = "clown"
desc = "Even looking at the card strikes you with deep fear."
access = list(ACCESS_CLOWN, ACCESS_THEATRE, ACCESS_MAINT_TUNNELS)
/obj/item/card/id/mime
name = "Black and White ID"
registered_name = "..."
icon_state = "mime"
desc = "..."
access = list(ACCESS_MIME, ACCESS_THEATRE, ACCESS_MAINT_TUNNELS)
/obj/item/card/id/botanist
name = "Botanist ID"
registered_name = "Botanist"
icon_state = "botanist"
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE)
/obj/item/card/id/librarian
name = "Librarian ID"
registered_name = "Librarian"
icon_state = "librarian"
access = list(ACCESS_LIBRARY, ACCESS_MAINT_TUNNELS)
/obj/item/card/id/chaplain
name = "Chaplain ID"
registered_name = "Chaplain"
icon_state = "chaplain"
access = list(ACCESS_MORGUE, ACCESS_CHAPEL_OFFICE, ACCESS_CREMATORIUM, ACCESS_MAINT_TUNNELS)
/obj/item/card/id/bartender
name = "Bartender ID"
registered_name = "Bartender"
icon_state = "bartender"
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE, ACCESS_WEAPONS, ACCESS_MINERAL_STOREROOM)
/obj/item/card/id/chef
name = "Chef ID"
registered_name = "Chef"
icon_state = "chef"
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE)
/obj/item/card/id/janitor
name = "Janitor ID"
registered_name = "Janitor"
icon_state = "janitor"
access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_MORGUE)
/obj/item/card/id/explorer
name = "Explorer ID"
registered_name = "Explorer"
icon_state = "explorer"
/obj/item/card/id/rainbow
name = "Rainbow ID"
icon_state = "rainbow"
/obj/item/card/id/thunderdome/red
name = "Thunderdome Red ID"
registered_name = "Red Team Fighter"
assignment = "Red Team Fighter"
icon_state = "TDred"
desc = "This ID card is given to those who fought inside the thunderdome for the Red Team. Not many have lived to see one of those, even fewer lived to keep it."
/obj/item/card/id/thunderdome/green
name = "Thunderdome Green ID"
registered_name = "Green Team Fighter"
assignment = "Green Team Fighter"
icon_state = "TDgreen"
desc = "This ID card is given to those who fought inside the thunderdome for the Green Team. Not many have lived to see one of those, even fewer lived to keep it."
/obj/item/card/id/lifetime
name = "Lifetime ID Card"
desc = "A modified ID card given only to those people who have devoted their lives to the better interests of Nanotrasen. It sparkles blue."
icon_state = "lifetimeid"
/obj/item/card/id/ert
name = "ERT ID"
icon_state = "ERT_empty"
/obj/item/card/id/ert/commander
icon_state = "ERT_leader"
/obj/item/card/id/ert/security
icon_state = "ERT_security"
/obj/item/card/id/ert/engineering
icon_state = "ERT_engineering"
/obj/item/card/id/ert/medic
icon_state = "ERT_medical"
/obj/item/card/id/ert/paranormal
icon_state = "ERT_paranormal"
/obj/item/card/id/ert/janitorial
icon_state = "ERT_janitorial"
/obj/item/card/id/ert/deathsquad
icon_state = "deathsquad"
/obj/item/card/id/golem
name = "Free Golem ID"
desc = "A card used to claim mining points and buy gear. Use it to mark it as yours."
icon_state = "research"
access = list(ACCESS_FREE_GOLEMS, ACCESS_ROBOTICS, ACCESS_CLOWN, ACCESS_MIME, ACCESS_XENOBIOLOGY, ACCESS_SMITH) //access to robots/mechs
can_id_flash = FALSE //So you do not flash it the first time you use it.
var/registered = FALSE
/obj/item/card/id/golem/activate_self(mob/user)
if(..())
return
if(!registered && ishuman(user))
registered_name = user.real_name
SetOwnerInfo(user)
assignment = "Free Golem"
RebuildHTML()
UpdateName()
desc = "A card used to claim mining points and buy gear."
registered = TRUE
can_id_flash = TRUE
to_chat(user, "<span class='notice'>The ID is now registered as yours.</span>")
/obj/item/card/id/data
icon_state = "data"
/obj/item/card/id/nct_data_chip
name = "\improper NCT Trainee Access Chip"
desc = "A small electronic access token that allows its user to copy the access of their Trainee. Only accessible by NT Career Trainers!"
icon_state = "nct_chip"
assignment = "Nanotrasen Career Trainer"
var/registered_user = null
var/trainee = null
/obj/item/card/id/nct_data_chip/examine(mob/user)
. = ..()
. += "<br>The current registered Trainee is: <b>[trainee]</b>"
. += "<span class='notice'>Use in hand to reset the assigned trainee and access.</span>"
. += "<span class='purple'>The datachip is unable to copy any access that has been deemed high-risk by Nanotrasen Officials. That includes some, if not most, head related access permissions.</span>"
/obj/item/card/id/nct_data_chip/activate_self(mob/user)
if(..())
return
if(!trainee)
return
var/response = tgui_alert(user, "Would you like to remove [trainee] as your current active Trainee?", "Choose", list("Yes", "No"))
if(response == "Yes")
trainee = null
icon_state = "nct_chip"
access = list()
/obj/item/card/id/nct_data_chip/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!istype(target, /obj/item/card/id))
return
if(!(isliving(user) && user.mind))
return
if(user.mind.current != registered_user)
to_chat(user, "<span class='notice'>You do not have access to use this NCT Trainee Access Chip!</span>")
return
if(istype(target, /obj/item/card/id/ert))
to_chat(user, "<span class='warning'>The chip's screen blinks red as you attempt scanning this ID.</span>")
return
var/obj/item/card/id/I = target
to_chat(user, "<span class='notice'>The chip's microscanners activate as you scan [I.registered_name]'s ID, copying its access.</span>")
access = I.access.Copy()
access.Remove(ACCESS_AI_UPLOAD, ACCESS_ARMORY, ACCESS_CAPTAIN, ACCESS_CE, ACCESS_RD, ACCESS_HOP, ACCESS_QM, ACCESS_CMO, ACCESS_HOS, ACCESS_NTREP,
ACCESS_MAGISTRATE, ACCESS_BLUESHIELD, ACCESS_HEADS_VAULT, ACCESS_KEYCARD_AUTH, ACCESS_RC_ANNOUNCE,
ACCESS_CHANGE_IDS, ACCESS_MINISAT)
trainee = I.registered_name
icon_state = "nct_chip_active"
/obj/item/card/id/syndicate_fake // Syndicate ID drip with none of the access theft or anti-tracking.
name = "\improper Syndicate ID card"
desc = "An evil-looking ID issued to members of the Syndicate."
icon_state = "syndie"
// Decals
/obj/item/id_decal
name = "identification card decal"
desc = "A nano-cellophane wrap that molds to an ID card to make it look snazzy."
icon = 'icons/obj/toy.dmi'
icon_state = "id_decal"
var/decal_name = "identification card"
var/decal_desc = "A card used to provide ID and determine access across the station."
var/decal_icon_state = "id"
var/decal_item_state = "card-id"
var/override_name = 0
/obj/item/id_decal/gold
name = "gold ID card decal"
icon_state = "id_decal_gold"
desc = "Make your ID look like the Captain's or a self-centered HOP's. Applies to any ID."
decal_desc = "A golden card which shows power and might."
decal_icon_state = "gold"
decal_item_state = "gold_id"
/obj/item/id_decal/silver
name = "silver ID card decal"
icon_state = "id_decal_silver"
desc = "Make your ID look like HOP's because they wouldn't change it officially. Applies to any ID."
decal_desc = "A silver card which shows honour and dedication."
decal_icon_state = "silver"
decal_item_state = "silver_id"
/obj/item/id_decal/prisoner
name = "prisoner ID card decal"
icon_state = "id_decal_prisoner"
desc = "All the cool kids have an ID that's this color. Applies to any ID."
decal_desc = "You are a number, you are not a free man."
decal_icon_state = "prisoner"
decal_item_state = "orange-id"
/obj/item/id_decal/centcom
name = "centcom ID card decal"
icon_state = "id_decal_centcom"
desc = "All the prestige without the responsibility or the access. Applies to any ID."
decal_desc = "An ID straight from Cent. Com."
decal_icon_state = "centcom"
/obj/item/id_decal/emag
name = "cryptographic sequencer ID card decal"
icon_state = "id_decal_emag"
desc = "A bundle of wires that you can tape to your ID to look very suspect. Applies to any ID."
decal_name = "cryptographic sequencer"
decal_desc = "It's a card with a magnetic strip attached to some circuitry."
decal_icon_state = "emag"
override_name = 1
/proc/get_station_card_skins()
return list("data", "id", "gold", "silver", "security", "detective", "warden", "internalaffairsagent", "medical", "coroner", "chemist", "virologist", "paramedic", "psychiatrist", "geneticist", "research", "roboticist", "quartermaster", "cargo", "shaftminer", "engineering", "atmostech", "captain", "HoP", "HoS", "CMO", "RD", "CE", "assistant", "clown", "mime", "botanist", "librarian", "chaplain", "bartender", "chef", "janitor", "rainbow", "prisoner", "explorer", "nct")
/proc/get_centcom_card_skins()
return list("centcom", "blueshield", "magistrate", "ntrep", "ERT_leader", "ERT_empty", "ERT_security", "ERT_engineering", "ERT_medical", "ERT_janitorial", "ERT_paranormal", "deathsquad", "commander", "syndie", "TDred", "TDgreen")
/proc/get_all_card_skins()
return get_station_card_skins() + get_centcom_card_skins()
/proc/get_skin_desc(skin)
switch(skin)
if("id")
return "Blank"
if("cargo")
return "Cargo Technician"
if("shaftminer")
return "Shaft Miner"
if("medical")
return "Medical Doctor"
if("engineering")
return "Station Engineer"
if("security")
return "Security Officer"
if("internalaffairsagent")
return "Internal Affairs Agent"
if("nct")
return "Nanotrasen Career Trainer"
if("atmostech")
return "Life Support Specialist"
if("HoP")
return "Head of Personal"
if("HoS")
return "Head of Security"
if("CMO")
return "Chief Medical Officer"
if("RD")
return "Research Director"
if("CE")
return "Chief Engineer"
if("ERT_leader")
return "ERT Leader"
if("ERT_empty")
return "ERT Default"
if("ERT_security")
return "ERT Security"
if("ERT_engineering")
return "ERT Engineering"
if("ERT_medical")
return "ERT Medical"
if("ERT_janitorial")
return "ERT Janitorial"
if("ERT_paranormal")
return "ERT Paranormal"
if("deathsquad")
return "Deathsquad"
if("syndie")
return "Syndicate"
if("TDred")
return "Thunderdome Red"
if("TDgreen")
return "Thunderdome Green"
else
return capitalize(skin)
/proc/GetNameAndAssignmentFromId(obj/item/card/id/I)
// Format currently matches that of newscaster feeds: Registered Name (Assigned Rank)
return I.assignment ? "[I.registered_name] ([I.assignment])" : I.registered_name
-83
View File
@@ -1,83 +0,0 @@
/obj/item/stack/spacecash
name = "1 Credit"
desc = "Money money money."
icon = 'icons/obj/money.dmi'
icon_state = "cash"
hitsound = "swing_hit"
throw_speed = 1
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
singular_name = "credit"
max_amount = MAX_STACKABLE_CASH
merge_type = /obj/item/stack/spacecash
/obj/item/stack/spacecash/Initialize(mapload)
. = ..()
SSeconomy.space_credits_created += amount
SSeconomy.total_space_cash += amount
update_icon(UPDATE_ICON_STATE)
/obj/item/stack/spacecash/Destroy()
SSeconomy.total_space_cash -= amount
SSeconomy.space_credits_destroyed += amount
return ..()
/obj/item/stack/spacecash/merge(obj/item/stack/S)
. = ..()
update_icon(UPDATE_ICON_STATE)
/obj/item/stack/spacecash/change_stack(mob/living/user)
. = ..()
var/obj/item/stack/spacecash/new_dosh = .
if(istype(new_dosh))
new_dosh.update_icon(UPDATE_ICON_STATE)
update_icon(UPDATE_ICON_STATE)
/obj/item/stack/spacecash/update_icon_state()
name = "[amount] Credit[amount > 1 ? "s" : ""]"
if(amount >= 1 && amount < 50)
icon_state = "cash"
else if(amount >= 50 && amount < 100)
icon_state = "cash2"
else if(amount >= 100 && amount < 500)
icon_state = "cash3"
else if(amount >= 500 && amount < 1000)
icon_state = "cash4"
else if(amount >= 1000 && amount < 10000)
icon_state = "cash5"
else
icon_state = "cash6"
/obj/item/stack/spacecash/c5
amount = 5
/obj/item/stack/spacecash/c10
amount = 10
/obj/item/stack/spacecash/c20
amount = 20
/obj/item/stack/spacecash/c50
amount = 50
/obj/item/stack/spacecash/c100
amount = 100
/obj/item/stack/spacecash/c200
amount = 200
/obj/item/stack/spacecash/c500
amount = 500
/obj/item/stack/spacecash/c1000
amount = 1000
/obj/item/stack/spacecash/c10000
amount = 10000
/obj/item/cash_pile
name = "Pile of Cash"
/obj/item/cash_pile/Initialize(mapload)
. = ..()
AddComponent(/datum/component/two_handed, require_twohands = TRUE)
@@ -1,97 +0,0 @@
/obj/item/caution
desc = "Caution! Wet Floor!"
name = "wet floor sign"
icon = 'icons/obj/janitor.dmi'
icon_state = "caution"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
force = 1.0
throwforce = 3.0
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("warned", "cautioned", "smashed")
/obj/item/caution/proximity_sign
var/timing = FALSE
var/armed = FALSE
var/timepassed = 0
var/datum/proximity_monitor/proximity_monitor
/obj/item/caution/proximity_sign/Initialize(mapload)
. = ..()
proximity_monitor = new(src, 1)
/obj/item/caution/proximity_sign/attack_self__legacy__attackchain(mob/user as mob)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(!H.mind.has_antag_datum(/datum/antagonist/traitor) && !IS_MINDSLAVE(H))
return
if(armed)
armed = FALSE
to_chat(user, "<span class='notice'>You disarm \the [src].</span>")
return
timing = !timing
if(timing)
START_PROCESSING(SSobj, src)
else
armed = FALSE
timepassed = 0
to_chat(H, "<span class='notice'>You [timing ? "activate \the [src]'s timer, you have 15 seconds." : "de-activate \the [src]'s timer."]</span>")
/obj/item/caution/proximity_sign/process()
if(!timing)
STOP_PROCESSING(SSobj, src)
timepassed++
if(timepassed >= 15 && !armed)
armed = TRUE
timing = FALSE
/obj/item/caution/proximity_sign/HasProximity(atom/movable/AM)
if(armed)
if(iscarbon(AM) && !isbrain(AM))
var/mob/living/carbon/C = AM
if(C.m_intent != MOVE_INTENT_WALK)
visible_message("[src] beeps, \"Sign says walk, asshole.\"")
playsound(src, 'sound/misc/sign_says_walk.ogg', 40)
explosion(src.loc,-1,0,2, cause = "Exploding wet floor sign")
if(ishuman(C))
dead_legs(C)
if(src)
qdel(src)
/obj/item/caution/proximity_sign/proc/dead_legs(mob/living/carbon/human/H as mob)
var/obj/item/organ/external/l = H.get_organ("l_leg")
var/obj/item/organ/external/r = H.get_organ("r_leg")
if(l)
l.droplimb(0, DROPLIMB_SHARP)
if(r)
r.droplimb(0, DROPLIMB_SHARP)
/obj/item/stack/caution/proximity_sign/malf //Malf module
name = "proximity mine dispenser"
icon = 'icons/obj/janitor.dmi'
icon_state = "caution"
energy_type = /datum/robot_storage/energy/jani_landmine
is_cyborg = TRUE
/obj/item/stack/caution/proximity_sign/malf/afterattack__legacy__attackchain(atom/target, mob/user, proximity)
if(!check_allowed_items(target, 1))
return
if(!proximity)
return
var/turf/T = get_turf(target)
if(T.is_blocked_turf(exclude_mobs = TRUE)) //can't put mines on a tile that has dense stuff
to_chat(user, "<span class='notice'>The space is occupied! You cannot place a mine there!</span>")
return
if(!use(1)) //Can't place a landmine if you don't have a landmine
to_chat(user, "<span class='notice'>[src] is out of landmines! It can be refilled at a cyborg charger.</span>")
return
playsound(src.loc, 'sound/machines/click.ogg', 20, TRUE)
var/obj/item/caution/proximity_sign/M = new /obj/item/caution/proximity_sign(get_turf(target), src)
M.timing = TRUE
START_PROCESSING(SSobj, M)
to_chat(user, "<span class='notice'>You place a landmine with [src]. You have 15 seconds until it is armed.</span>")
return M
-719
View File
@@ -1,719 +0,0 @@
#define REAGENT_TIME_RATIO 2.5
/*
CONTENTS:
1. CIGARETTES
2. CIGARS
3. HOLO-CIGAR
4. PIPES
5. ROLLING
CIGARETTE PACKETS ARE IN FANCY.DM
LIGHTERS ARE IN LIGHTERS.DM
*/
//////////////////
//FINE SMOKABLES//
//////////////////
/obj/item/clothing/mask/cigarette
name = "cigarette"
desc = "A roll of tobacco and nicotine."
icon = 'icons/obj/clothing/smoking.dmi'
icon_state = "cig"
lefthand_file = 'icons/mob/inhands/smoking_lefthand.dmi'
righthand_file = 'icons/mob/inhands/smoking_righthand.dmi'
w_class = WEIGHT_CLASS_TINY
body_parts_covered = null
attack_verb = null
container_type = INJECTABLE
new_attack_chain = TRUE
/// Is the cigarette lit?
var/lit = FALSE
/// Do we require special items to be lit?
var/list/fancy_lighters = list()
/// What trash item the cigarette makes when it burns out.
var/butt_type = /obj/item/cigbutt
/// How long does the cigarette last before going out? Decrements by 1 every cycle.
var/smoketime = 150 // 300 seconds.
/// The cigarette's total reagent capacity.
var/chem_volume = 60
/// A list of the types and amounts of reagents in the cigarette.
var/list/list_reagents = list("nicotine" = 40)
/// Has anyone taken any reagents from the cigarette? The first tick gives a bigger dose.
var/first_puff = TRUE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/mask.dmi',
"Unathi" = 'icons/mob/clothing/species/unathi/mask.dmi',
"Tajaran" = 'icons/mob/clothing/species/tajaran/mask.dmi',
"Vulpkanin" = 'icons/mob/clothing/species/vulpkanin/mask.dmi',
"Grey" = 'icons/mob/clothing/species/grey/mask.dmi')
/obj/item/clothing/mask/cigarette/Initialize(mapload)
. = ..()
create_reagents(chem_volume) // making the cigarrete a chemical holder with a maximum volume of 60
reagents.set_reacting(FALSE) // so it doesn't react until you light it
if(list_reagents)
reagents.add_reagent_list(list_reagents)
smoketime = reagents.total_volume * 2.5
update_appearance(UPDATE_NAME|UPDATE_ICON_STATE)
/obj/item/clothing/mask/cigarette/update_icon_state()
. = ..()
icon_state = "[initial(icon_state)][lit ? "_on" : ""]"
item_state = "[initial(icon_state)][lit ? "_on" : ""]"
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
H.update_inv_wear_mask()
H.update_inv_l_hand()
H.update_inv_r_hand()
/obj/item/clothing/mask/cigarette/update_name()
. = ..()
if(!lit)
name = initial(name)
else
name = "lit [name]"
/obj/item/clothing/mask/cigarette/activate_self(mob/user)
if(..())
return
if(lit)
extinguish_cigarette(user)
/obj/item/clothing/mask/cigarette/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(istype(used, /obj/item/reagent_containers/syringe))
return ..()
if(used.cigarette_lighter_act(user, user, src))
return ITEM_INTERACT_COMPLETE
// Catch any item that has no `cigarette_lighter_act()` but logically should be able to work as a lighter due to being hot.
if(used.get_heat())
//Give a generic light message.
user.visible_message(
"<span class='notice'>[user] lights [src] with [used]</span>",
"<span class='notice'>You light [src] with [used].</span>"
)
light(user)
return ITEM_INTERACT_COMPLETE
return ..()
/obj/item/clothing/mask/cigarette/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!istype(target, /obj/item/reagent_containers/glass))
return ..()
var/obj/item/reagent_containers/glass/glass = target
var/transfered = glass.reagents.trans_to(src, chem_volume)
if(transfered)
to_chat(user, "<span class='notice'>You dip [src] into [target].</span>")
return ITEM_INTERACT_COMPLETE
// Either the beaker was empty, or the cigarette was full
if(!glass.reagents.total_volume)
to_chat(user, "<span class='notice'>[target] is empty.</span>")
else
to_chat(user, "<span class='notice'>[src] is full.</span>")
return ITEM_INTERACT_COMPLETE
/obj/item/clothing/mask/cigarette/pre_attack(atom/A, mob/living/user, params)
if(!ismob(A))
return ..()
var/mob/living/target = A
if(target.on_fire)
user.changeNext_move(CLICK_CD_MELEE)
user.do_attack_animation(target)
if(target != user)
user.visible_message(
"<span class='notice'>[user] coldly lights [src] with the burning body of [target]. Clearly, [user.p_they()] offer[user.p_s()] the warmest of regards...</span>",
"<span class='notice'>You coldly light [src] with the burning body of [target].</span>"
)
else
// The fire will light it in your hands by itself, but if you whip out the cig and click yourself fast enough, this will happen. TRULY you have your priorities stright.
user.visible_message(
"<span class='notice'>[user] quickly whips out [src] and nonchalantly lights it with [user.p_their()] own burning body. Clearly, [user.p_they()] [user.p_have()] [user.p_their()] priorities straight.</span>",
"<span class='notice'>You quickly whip out [src] and nonchalantly light it with your own burning body. Clearly, you have your priorities straight.</span>"
)
light(user, user)
return FINISH_ATTACK
// The above section doesn't check for carbons to allow ALL burning bodies to be used.
if(!iscarbon(A))
return ..()
// If the target has no cig, try to give them the cig.
var/mob/living/carbon_target = A
if(user.zone_selected == "mouth" && !carbon_target.wear_mask && user.a_intent == INTENT_HELP)
user.drop_item_to_ground(src, force = TRUE)
carbon_target.equip_to_slot_if_possible(src, ITEM_SLOT_MASK)
if(target != user)
user.visible_message(
"<span class='notice'>[user] slips \a [name] into the mouth of [carbon_target].</span>",
"<span class='notice'>You slip [src] into the mouth of [carbon_target].</span>"
)
else
to_chat(user, "<span class='notice'>You put [src] into your mouth.</span>")
return FINISH_ATTACK
// If they DO have a cig, try to light it with your own cig.
if(cigarette_lighter_act(user, carbon_target))
return FINISH_ATTACK
return ..()
/obj/item/clothing/mask/cigarette/Destroy()
QDEL_NULL(reagents)
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/clothing/mask/cigarette/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(isdrone(user))
C.stored_comms["wood"] += 1
qdel(src)
return TRUE
return ..()
/obj/item/clothing/mask/cigarette/proc/extinguish_cigarette(mob/user)
user.visible_message(
"<span class='notice'>[user] calmly drops and treads on [src], putting it out instantly.</span>",
"<span class='notice'>You calmly drop and tread on [src], putting it out instantly.</span>",
"<span class='notice'>You hear a foot being brought down on something, and the tiny fizzling of an ember going out.</span>"
)
die()
/obj/item/clothing/mask/cigarette/can_enter_storage(obj/item/storage/S, mob/user)
if(lit)
to_chat(user, "<span class='warning'>[S] can't hold \the [initial(name)] while it's lit!</span>") // initial(name) so it doesn't say "lit" twice in a row
return FALSE
return TRUE
/obj/item/clothing/mask/cigarette/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
light()
/obj/item/clothing/mask/cigarette/catch_fire()
if(!lit)
visible_message("<span class='warning'>[src] is lit by the flames!</span>")
light()
/obj/item/clothing/mask/cigarette/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
var/obj/item/clothing/mask/cigarette/cig = ..()
if(!cig)
return !isnull(cig)
if(!lit)
to_chat(user, "<span class='warning'>You cannot light [cig] with [src] because you need a lighter to light [src] before you can use [src] as a lighter to light [cig]... This seems a little convoluted.</span>")
return TRUE
if(target == user)
user.visible_message(
"<span class='notice'>[user] presses [src] against [cig] until it lights. Seems oddly recursive...</span>",
"<span class='notice'>You press [src] against [cig] until it lights. Seems oddly recursive...</span>"
)
else
user.visible_message(
"<span class='notice'>[user] presses [src] until it lights. Sharing is caring!</span>",
"<span class='notice'>You press [src] against [cig] until it lights. Sharing is caring!</span>"
)
cig.light(user, target)
return TRUE
/obj/item/clothing/mask/cigarette/proc/light(mob/living/user, mob/living/target)
if(lit)
return
lit = TRUE
attack_verb = list("burnt", "singed")
hitsound = 'sound/items/welder.ogg'
damtype = BURN
force = 4
var/mob/M = loc
// Plasma explodes when exposed to fire.
if(reagents.get_reagent_amount("plasma"))
var/datum/effect_system/reagents_explosion/e = new()
e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0)
e.start()
if(ismob(M))
M.drop_item_to_ground(src, force = TRUE)
qdel(src)
return
// Fuel explodes, too, but much less violently.
if(reagents.get_reagent_amount("fuel"))
var/datum/effect_system/reagents_explosion/e = new()
e.set_up(round(reagents.get_reagent_amount("fuel") / 5, 1), get_turf(src), 0, 0)
e.start()
if(ismob(M))
M.drop_item_to_ground(src, force = TRUE)
qdel(src)
return
// If there is no target, the user is probably lighting their own cig.
if(isnull(target))
target = user
reagents.set_reacting(TRUE)
reagents.handle_reactions()
if(iscarbon(loc))
var/mob/living/carbon/C = loc
if(C.wear_mask == src) // Don't update if it's just in their hand
C.wear_mask_update(src)
set_light(2, 0.25, "#E38F46")
update_appearance(UPDATE_NAME|UPDATE_ICON_STATE)
START_PROCESSING(SSobj, src)
playsound(src, 'sound/items/lighter/light.ogg', 25, TRUE)
return TRUE
/obj/item/clothing/mask/cigarette/process()
var/mob/living/M = loc
if(isliving(loc))
M.IgniteMob()
smoketime--
if(reagents.total_volume <= 0 || smoketime < 1)
die()
return
smoke()
/obj/item/clothing/mask/cigarette/extinguish_light(force)
if(!force)
return
die()
/obj/item/clothing/mask/cigarette/proc/smoke()
var/turf/location = get_turf(src)
var/is_being_smoked = FALSE
// Check whether this is actually in a mouth, being smoked
if(iscarbon(loc))
var/mob/living/carbon/C = loc
if(src == C.wear_mask)
// There used to be a species check here, but synthetics can smoke now
is_being_smoked = TRUE
if(location)
location.hotspot_expose(700, 1)
if(reagents && reagents.total_volume) // check if it has any reagents at all
if(is_being_smoked) // if it's being smoked, transfer reagents to the mob
var/mob/living/carbon/C = loc
for(var/datum/reagent/R in reagents.reagent_list)
reagents.trans_id_to(C, R.id, first_puff ? 1 : max(REAGENTS_METABOLISM / length(reagents.reagent_list), 0.1)) //transfer at least .1 of each chem
first_puff = FALSE
if(!reagents.total_volume) // There were reagents, but now they're gone
to_chat(C, "<span class='notice'>Your [name] loses its flavor.</span>")
else // else just remove some of the reagents
reagents.remove_any(REAGENTS_METABOLISM)
/obj/item/clothing/mask/cigarette/proc/die()
var/turf/T = get_turf(src)
set_light(0)
var/obj/item/butt = new butt_type(T)
transfer_fingerprints_to(butt)
if(ismob(loc))
var/mob/living/M = loc
to_chat(M, "<span class='notice'>Your [name] goes out.</span>")
// Only put the butt in the user's mouth if there's already a cig there.
if(M.wear_mask == src)
M.drop_item_to_ground(src, force = TRUE) //Force the un-equip so the overlays update
butt.slot_flags |= ITEM_SLOT_MASK // Temporarily allow it to go on masks
M.equip_to_slot_if_possible(butt, ITEM_SLOT_MASK)
butt.slot_flags &= ~ITEM_SLOT_MASK
else
M.drop_item_to_ground(src, force = TRUE)
STOP_PROCESSING(SSobj, src)
qdel(src)
/obj/item/clothing/mask/cigarette/get_heat()
return lit * 1000
//////////////////////////////
// MARK: CIGARETTES
//////////////////////////////
/obj/item/clothing/mask/cigarette/menthol
list_reagents = list("nicotine" = 40, "menthol" = 20)
/obj/item/clothing/mask/cigarette/random
/obj/item/clothing/mask/cigarette/random/New()
list_reagents = list("nicotine" = 40, pick("fuel", "saltpetre", "synaptizine", "green_vomit", "potass_iodide", "msg", "lexorin", "mannitol", \
"spaceacillin" ,"cryoxadone" ,"holywater", "tea" ,"egg" ,"haloperidol" ,"mutagen" ,"omnizine", "carpet", "aranesp", "cryostylane", "chocolate", \
"bilk", "cheese", "rum", "blood", "charcoal", "coffee", "ectoplasm", "space_drugs", "milk", "mutadone", "antihol", "teporone", "insulin", "salbutamol", "toxin") = 20)
..()
/obj/item/clothing/mask/cigarette/candy
name = "candy cigarette"
desc = "A stick of candy imitating a real cigarette. The words 'do not expose to heat' are written in very small letters around the base."
/obj/item/clothing/mask/cigarette/candy/interact_with_atom(atom/A, mob/living/user, list/modifiers)
if(..())
return
if(!ishuman(A))
return
var/mob/living/carbon/human/target = A
if(target != user)
user.visible_message(
"<span_class='notice'>You begin to feed [target] [src].</span>",
"<span_class='warning'>[user] begins to feed [target] [src]!</span>"
)
if(!do_after(user, 5 SECONDS, target = target))
return ITEM_INTERACT_COMPLETE
else
to_chat(user, "<span_class='notice'>You eat [src].</span>")
playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0)
// A SPICY candy!
if(lit)
target.adjust_nutrition(2)
target.reagents.add_reagent("sugar", 2, reagtemp = 373)
target.reagents.add_reagent("ash", 3, reagtemp = 373)
target.reagents.add_reagent("nicotine", 3, reagtemp = 373)
var/obj/item/organ/external/head/target_head = target.get_organ("head")
if(target_head.receive_damage(0, 15)) // OH GOD IT BURNS WHY DID I EAT THIS!?
target.UpdateDamageIcon()
to_chat(target, "<span_class='notice'>You can taste burnt sugar, ash, burning chemicals, and your own burning flesh...</span>")
to_chat(target, "<span_class='userdanger'>OH FUCK! IT BURNS!</span>")
target.emote("scream")
add_attack_logs(user, target, "Fed a burning candy cigarette.")
else
target.adjust_nutrition(5)
target.reagents.add_reagent("sugar", 5)
to_chat(target, "<span_class='notice'>You can taste sugar, and a hint of chemicals.</span>")
qdel(src)
return ITEM_INTERACT_COMPLETE
/obj/item/clothing/mask/cigarette/syndicate
name = "suspicious cigarette"
desc = "An evil-looking cigarette. It smells of donk pockets."
icon_state = "syndie_cig"
butt_type = /obj/item/cigbutt/syndie
list_reagents = list("nicotine" = 40, "omnizine" = 20)
/obj/item/clothing/mask/cigarette/medical_marijuana
name = "medical marijuana cigarette"
desc = "A cigarette containing specially-bread cannabis that has been engineered to only contain CBD, for medical use. The lack of THC makes it fully legal under Space Law."
icon_state = "medical_weed_cig"
list_reagents = list("cbd" = 60)
/obj/item/clothing/mask/cigarette/robustgold
name = "\improper Robust Gold cigarette"
desc = "A premium cigarette smoked by the truly robust, contains real gold."
list_reagents = list("nicotine" = 40, "gold" = 1)
/obj/item/clothing/mask/cigarette/shadyjims
list_reagents = list("nicotine" = 40, "lipolicide" = 7.5, "ammonia" = 2, "atrazine" = 1, "toxin" = 1.5)
/obj/item/clothing/mask/cigarette/rollie
name = "rollie"
desc = "A roll of dried plant matter wrapped in thin paper. It carries the unmistakable smell of cannabis."
icon_state = "spliff"
butt_type = /obj/item/cigbutt/roach
list_reagents = list("thc" = 40, "cbd" = 20)
/obj/item/clothing/mask/cigarette/rollie/Initialize(mapload)
. = ..()
scatter_atom()
/obj/item/clothing/mask/cigarette/rollie/custom
desc = "A roll of dried plant matter wrapped in thin paper."
list_reagents = list()
/obj/item/cigbutt
name = "cigarette butt"
desc = "A manky old cigarette butt."
icon = 'icons/obj/clothing/smoking.dmi'
icon_state = "cig_butt"
w_class = WEIGHT_CLASS_TINY
scatter_distance = 10
/obj/item/cigbutt/syndie
name = "suspicious cigarette butt"
desc = "A manky old cigarette butt with an evil look about it."
icon_state = "syndie_cig_butt"
/obj/item/cigbutt/Initialize(mapload)
. = ..()
scatter_atom()
transform = turn(transform, rand(0, 360))
/obj/item/cigbutt/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(isdrone(user))
C.stored_comms["wood"] += 1
qdel(src)
return TRUE
return ..()
/obj/item/cigbutt/roach
name = "roach"
desc = "A manky old roach, or for non-stoners, a used rollup."
icon_state = "roach"
scatter_distance = 5
/obj/item/cigbutt/roach/Initialize(mapload)
. = ..()
scatter_atom()
//////////////////////////////
// MARK: ROLLING
//////////////////////////////
/obj/item/rollingpaper
name = "rolling paper"
desc = "A thin piece of paper used to make fine smokeables."
icon = 'icons/obj/cigarettes.dmi'
icon_state = "cig_paper"
w_class = WEIGHT_CLASS_TINY
new_attack_chain = TRUE
/obj/item/rollingpaper/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(!istype(used, /obj/item/food/grown))
return ..()
var/obj/item/food/grown/plant = used
if(!plant.dry)
to_chat(user, "<span class='warning'>You need to dry this first!</span>")
return ITEM_INTERACT_COMPLETE
user.unequip(plant, TRUE)
user.unequip(src, TRUE)
var/obj/item/clothing/mask/cigarette/rollie/custom/custom_rollie = new (get_turf(user))
custom_rollie.reagents.maximum_volume = plant.reagents.total_volume
plant.reagents.trans_to(custom_rollie, plant.reagents.total_volume)
custom_rollie.smoketime = custom_rollie.reagents.total_volume * 2.5
user.put_in_active_hand(custom_rollie)
to_chat(user, "<span class='notice'>You roll the [plant.name] into a rolling paper.</span>")
custom_rollie.desc = "Dried [plant.name] rolled up in a thin piece of paper."
qdel(plant)
qdel(src)
return ITEM_INTERACT_COMPLETE
//////////////////////////////
// MARK: CIGARS
//////////////////////////////
/obj/item/clothing/mask/cigarette/cigar
name = "\improper Nano Cigar"
desc = "A huge, brown roll of dried and fermented tobacco, manufactured by Nanotrasen's Robust Tobacco subsidiary."
icon_state = "cigar"
fancy_lighters = list(/obj/item/match, /obj/item/lighter/zippo)
butt_type = /obj/item/cigbutt/cigarbutt
smoketime = 300
chem_volume = 140
list_reagents = list("nicotine" = 120)
/obj/item/clothing/mask/cigarette/cigar/examine_more(mob/user)
. = ..()
. += " Don't let the advertising fool you, this thing is a bargain basement, bottom-of-the-barrel product and the smoking experience it offers is little better than an oversized Robust cigarette."
. += ""
. += "It still makes you look like a mafia boss, however."
/obj/item/clothing/mask/cigarette/cigar/cohiba
name = "\improper Cohiba Robusto Cigar"
desc = "A premium brand of cigar widely exported and enjoyed across the Orion Sector. There's little more that you could want from a cigar"
icon_state = "gold_cigar"
butt_type = /obj/item/cigbutt/cigarbutt/gold
/obj/item/clothing/mask/cigarette/cigar/cohiba/examine_more(mob/user)
..()
. = list()
. += "Lovingly machine rolled using carefully selected strains of tobacco grown in massive hydroponics warehouses in orbit around the death world of Venus, Sol. \
It goes through a range of carefully selected flavours as it is smoked, providing a novel and enjoyable experience throughout."
/obj/item/clothing/mask/cigarette/cigar/havana
name = "\improper Premium Havanian Cigar"
desc = "A luxury cigar only fit for the best of the best."
icon_state = "gold_cigar"
smoketime = 450
chem_volume = 200
list_reagents = list("nicotine" = 180)
butt_type = /obj/item/cigbutt/cigarbutt/gold
/obj/item/clothing/mask/cigarette/cigar/havana/examine_more(mob/user)
..()
. = list()
. += "One of a handful of brands made using tobacco grown in Cuba on Earth, the core of the Trans-Solar Federation. \
Each of these hand-rolled cigars is carefully put together by master cigar rollers using various strains of tobacco that has been cultivated for hundreds of years to ensure \
the best consistency and flavour possible."
. += ""
. += "Due to a mixture of limited manufacturing capacity, high quality, brand prestige, and export taxes, \
these cigars are too expensive for all but the most wealthy to smoke with any degree of regularity."
/obj/item/cigbutt/cigarbutt
name = "cigar butt"
desc = "A manky old cigar butt."
icon_state = "cigar_butt"
/obj/item/cigbutt/cigarbutt/gold
icon_state = "gold_cigar_butt"
//////////////////////////////
// MARK: HOLO-CIGAR
//////////////////////////////
/obj/item/clothing/mask/holo_cigar
name = "holo-cigar"
desc = "A sleek electronic cigar imported straight from Sol. You feel badass merely glimpsing it..."
icon = 'icons/obj/clothing/smoking.dmi'
icon_state = "holo_cigar"
lefthand_file = 'icons/mob/inhands/smoking_lefthand.dmi'
righthand_file = 'icons/mob/inhands/smoking_righthand.dmi'
new_attack_chain = TRUE
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/mask.dmi',
"Unathi" = 'icons/mob/clothing/species/unathi/mask.dmi',
"Tajaran" = 'icons/mob/clothing/species/tajaran/mask.dmi',
"Vulpkanin" = 'icons/mob/clothing/species/vulpkanin/mask.dmi',
"Grey" = 'icons/mob/clothing/species/grey/mask.dmi')
/// Is the holo-cigar lit?
var/enabled = FALSE
/// Tracks if this is the first cycle smoking the cigar.
var/has_smoked = FALSE
/obj/item/clothing/mask/holo_cigar/activate_self(mob/user)
if(..())
return
if(enabled)
enabled = FALSE
to_chat(user, "<span class='notice'>You disable the holo-cigar.</span>")
STOP_PROCESSING(SSobj, src)
else
enabled = TRUE
to_chat(user, "<span class='notice'>You enable the holo-cigar.</span>")
START_PROCESSING(SSobj, src)
update_appearance(UPDATE_NAME|UPDATE_ICON_STATE)
/obj/item/clothing/mask/holo_cigar/Destroy()
. = ..()
STOP_PROCESSING(SSobj, src)
/obj/item/clothing/mask/holo_cigar/update_icon_state()
. = ..()
icon_state = "holo_cigar[enabled ? "_on" : ""]"
/obj/item/clothing/mask/holo_cigar/update_name()
. = ..()
name = "[enabled ? "active " : ""]holo-cigar"
/obj/item/clothing/mask/holo_cigar/examine(mob/user)
. = ..()
if(enabled)
. += "[src] hums softly as it synthesizes nicotine."
else
. += "[src] seems to be inactive."
/obj/item/clothing/mask/holo_cigar/process()
if(!iscarbon(loc))
return
var/mob/living/carbon/C = loc
if(C.wear_mask != src)
return
if(!has_smoked)
C.reagents.add_reagent("nicotine", 2)
has_smoked = TRUE
else
C.reagents.add_reagent("nicotine", REAGENTS_METABOLISM)
/obj/item/clothing/mask/holo_cigar/equipped(mob/user, slot, initial)
. = ..()
if(enabled && slot == ITEM_SLOT_MASK)
if(!HAS_TRAIT_FROM(user, TRAIT_BADASS, HOLO_CIGAR))
ADD_TRAIT(user, TRAIT_BADASS, HOLO_CIGAR)
to_chat(user, "<span class='notice'>You feel more badass while smoking [src].</span>")
/obj/item/clothing/mask/holo_cigar/dropped(mob/user, silent)
. = ..()
has_smoked = FALSE
if(HAS_TRAIT_FROM(user, TRAIT_BADASS, HOLO_CIGAR))
REMOVE_TRAIT(user, TRAIT_BADASS, HOLO_CIGAR)
to_chat(user, "<span class='notice'>You feel less badass.</span>")
//////////////////////////////
// MARK: PIPES
//////////////////////////////
/obj/item/clothing/mask/cigarette/pipe
name = "smoking pipe"
desc = "A fancy smoking pipe carved from polished morta, otherwise known as bog wood. Preferred by sophisticated gentlemen and those posing as sophisticated gentlemen."
icon_state = "pipe"
fancy_lighters = list(/obj/item/match, /obj/item/lighter/zippo)
smoketime = 500
chem_volume = 220
list_reagents = list("nicotine" = 200)
/obj/item/clothing/mask/cigarette/pipe/activate_self(mob/user)
if(..())
return
if(lit)
extinguish_cigarette(user)
/obj/item/clothing/mask/cigarette/pipe/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(!istype(used, /obj/item/food/grown))
return ..()
var/obj/item/food/grown/filler = used
if(!filler.dry)
to_chat(user, "<span class='warning'>You need to dry this first!</span>")
return ITEM_INTERACT_COMPLETE
if(reagents.total_volume == reagents.maximum_volume)
to_chat(user, "<span class='warning'>[src] is full!</span>")
return ITEM_INTERACT_COMPLETE
filler.reagents.trans_to(src, chem_volume)
to_chat(user, "<span class='notice'>You stuff the [filler.name] into the pipe.</span>")
smoketime = max(reagents.total_volume * REAGENT_TIME_RATIO, smoketime)
qdel(filler)
return ITEM_INTERACT_COMPLETE
/obj/item/clothing/mask/cigarette/pipe/light()
if(!lit)
lit = TRUE
damtype = "fire"
update_appearance(UPDATE_NAME|UPDATE_ICON_STATE)
START_PROCESSING(SSobj, src)
/obj/item/clothing/mask/cigarette/pipe/process()
var/turf/location = get_turf(src)
smoketime--
if(smoketime < 1)
new /obj/effect/decal/cleanable/ash(location)
if(ismob(loc))
var/mob/living/M = loc
to_chat(M, "<span class='notice'>Your [name] goes out, and you empty the ash.</span>")
lit = FALSE
update_appearance(UPDATE_NAME|UPDATE_ICON_STATE)
STOP_PROCESSING(SSobj, src)
return
smoke()
/obj/item/clothing/mask/cigarette/pipe/extinguish_cigarette(mob/user)
user.visible_message(
"<span class='notice'>[user] puts out [src].</span>",
"<span class='notice'>You put out [src].</span>"
)
lit = FALSE
first_puff = TRUE
update_appearance(UPDATE_NAME|UPDATE_ICON_STATE)
STOP_PROCESSING(SSobj, src)
/obj/item/clothing/mask/cigarette/pipe/die()
return
/obj/item/clothing/mask/cigarette/pipe/cobpipe
name = "corn cob pipe"
desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters."
icon_state = "cob_pipe"
smoketime = 0 //there is nothing to smoke initially
chem_volume = 160
list_reagents = list()
#undef REAGENT_TIME_RATIO
@@ -1,100 +0,0 @@
/* Clown Items
* Contains:
* Banana Peels
* Soap
* Bike Horns
*/
/*
* Bike Horns
*/
/obj/item/bikehorn
name = "bike horn"
desc = "A horn off of a bicycle."
icon_state = "bike_horn"
item_state = "bike_horn"
hitsound = null
throwforce = 3
w_class = WEIGHT_CLASS_TINY
var/list/honk_sounds = list('sound/items/bikehorn.ogg' = 1)
throw_speed = 3
throw_range = 15
attack_verb = list("HONKED")
/obj/item/bikehorn/Initialize(mapload)
. = ..()
AddComponent(/datum/component/squeak, honk_sounds, 50, falloff_exponent = 20) //die off quick please
/obj/item/bikehorn/airhorn
name = "air horn"
desc = "Damn son, where'd you find this?"
icon_state = "air_horn"
origin_tech = "materials=4;engineering=4"
honk_sounds = list('sound/items/airhorn2.ogg' = 1)
/obj/item/bikehorn/golden
name = "golden bike horn"
desc = "Golden? Clearly, its made with bananium! Honk!"
icon_state = "gold_horn"
item_state = "gold_horn"
var/cooldown = 0
/obj/item/bikehorn/golden/attack__legacy__attackchain(mob/M, mob/user)
flip_mobs(user)
return ..()
/obj/item/bikehorn/golden/attack_self__legacy__attackchain(mob/user)
flip_mobs(user)
..()
/obj/item/bikehorn/golden/proc/flip_mobs(mob/user)
if(cooldown >= world.time)
to_chat(user, "<span class='warning'>You can't make others flip yet!</span>")
return
cooldown = world.time + 30 SECONDS
var/turf/T = get_turf(src)
for(var/mob/living/carbon/M in ohearers(7, T))
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(!H.can_hear())
continue
M.emote("flip")
#define LAUGH_COOLDOWN 30 SECONDS
#define LAUGH_COOLDOWN_CMAG 10 SECONDS
/obj/item/clown_recorder
name = "clown recorder"
desc = "When you just can't get those laughs coming the natural way!"
icon = 'icons/obj/device.dmi'
icon_state = "clown_recorder"
item_state = "analyzer"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
materials = list(MAT_METAL = 180, MAT_GLASS = 90)
force = 2
drop_sound = 'sound/items/handling/taperecorder_drop.ogg'
pickup_sound = 'sound/items/handling/taperecorder_pickup.ogg'
actions_types = list(/datum/action/item_action/laugh_track)
var/cooldown = 0
/obj/item/clown_recorder/attack_self__legacy__attackchain(mob/user)
if(cooldown > world.time)
to_chat(user, "<span class='notice'>The tape is still winding back.</span>")
return
playsound(src, pick('sound/voice/sitcom_laugh.ogg', 'sound/voice/sitcom_laugh2.ogg'), 50, FALSE)
if(!HAS_TRAIT(src, TRAIT_CMAGGED))
cooldown = world.time + LAUGH_COOLDOWN
else
cooldown = world.time + LAUGH_COOLDOWN_CMAG
/obj/item/clown_recorder/cmag_act(mob/user)
if(!HAS_TRAIT(src, TRAIT_CMAGGED))
to_chat(user, "<span class='notice'>Winding back speed has been improved by the bananium ooze!</span>")
ADD_TRAIT(src, TRAIT_CMAGGED, CLOWN_EMAG)
return TRUE
return FALSE
#undef LAUGH_COOLDOWN
#undef LAUGH_COOLDOWN_CMAG
@@ -1,183 +0,0 @@
/obj/item/lipstick
name = "red lipstick"
desc = "A generic brand of lipstick."
icon_state = "lipstick"
w_class = WEIGHT_CLASS_TINY
var/colour = "red"
var/open = FALSE
var/static/list/lipstick_colors
/obj/item/lipstick/Initialize(mapload)
. = ..()
if(!lipstick_colors)
lipstick_colors = list(
"black" = "#000000",
"white" = "#FFFFFF",
"red" = "#FF0000",
"green" = "#00C000",
"blue" = "#0000FF",
"purple" = "#D55CD0",
"jade" = "#216F43",
"lime" = "#00FF00",
)
/obj/item/lipstick/purple
name = "purple lipstick"
colour = "purple"
/obj/item/lipstick/jade
name = "jade lipstick"
colour = "jade"
/obj/item/lipstick/lime
name = "lime lipstick"
colour = "lime"
/obj/item/lipstick/black
name = "black lipstick"
colour = "black"
/obj/item/lipstick/green
name = "green lipstick"
colour = "green"
/obj/item/lipstick/blue
name = "blue lipstick"
colour = "blue"
/obj/item/lipstick/white
name = "white lipstick"
colour = "white"
/obj/item/lipstick/random
name = "lipstick"
/obj/item/lipstick/random/Initialize(mapload)
. = ..()
colour = pick(lipstick_colors)
name = "[colour] lipstick"
/obj/item/lipstick/attack_self__legacy__attackchain(mob/user)
cut_overlays()
to_chat(user, "<span class='notice'>You twist \the [src] [open ? "closed" : "open"].</span>")
open = !open
if(open)
var/mutable_appearance/colored = mutable_appearance('icons/obj/items.dmi', "lipstick_uncap_color")
colored.color = lipstick_colors[colour]
icon_state = "lipstick_uncap"
add_overlay(colored)
else
icon_state = "lipstick"
/obj/item/lipstick/attack__legacy__attackchain(mob/M, mob/user)
if(!open || !istype(M))
return
if(ishuman(M))
var/mob/living/carbon/human/H = M
if(H.lip_style) // If they already have lipstick on
to_chat(user, "<span class='notice'>You need to wipe off the old lipstick first!</span>")
return
if(H == user)
user.visible_message("<span class='notice'>[user] does [user.p_their()] lips with [src].</span>", \
"<span class='notice'>You take a moment to apply [src]. Perfect!</span>")
H.lip_style = "lipstick"
H.lip_color = lipstick_colors[colour]
H.update_body()
else
user.visible_message("<span class='warning'>[user] begins to do [H]'s lips with \the [src].</span>", \
"<span class='notice'>You begin to apply \the [src].</span>")
if(do_after(user, 20, target = H))
user.visible_message("<span class='notice'>[user] does [H]'s lips with \the [src].</span>", \
"<span class='notice'>You apply \the [src].</span>")
H.lip_style = "lipstick"
H.lip_color = lipstick_colors[colour]
H.update_body()
else
to_chat(user, "<span class='notice'>Where are the lips on that?</span>")
/obj/item/razor
name = "electric razor"
desc = "The latest and greatest power razor born from the science of shaving."
icon_state = "razor"
flags = CONDUCT
w_class = WEIGHT_CLASS_TINY
usesound = 'sound/items/welder2.ogg'
/obj/item/razor/attack__legacy__attackchain(mob/living/carbon/M as mob, mob/user as mob)
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/obj/item/organ/external/head/C = H.get_organ("head")
if(!istype(C))
to_chat(user, "<span class='warning'>There's nothing to cut, [M] [M.p_are()] missing [M.p_their()] head!</span>")
return ..()
var/datum/robolimb/robohead = GLOB.all_robolimbs[C.model]
if(user.zone_selected == "mouth")
if(!get_location_accessible(H, "mouth"))
to_chat(user, "<span class='warning'>The mask is in the way.</span>")
return
if((C.dna.species.bodyflags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'...
to_chat(user, "<span class='warning'>You find yourself disappointed at the appalling lack of facial hair.</span>")
return
if(C.f_style == "Shaved")
to_chat(user, "<span class='notice'>Already clean-shaven.</span>")
return
if(H == user) //shaving yourself
user.visible_message("<span class='notice'>[user] starts to shave [user.p_their()] facial hair with [src].</span>", \
"<span class='notice'>You take a moment shave your facial hair with \the [src].</span>")
if(do_after(user, 50 * toolspeed, target = H))
user.visible_message("<span class='notice'>[user] shaves [user.p_their()] facial hair clean with [src].</span>", \
"<span class='notice'>You finish shaving with [src]. Fast and clean!</span>")
C.f_style = "Shaved"
H.update_fhair()
playsound(src.loc, usesound, 20, 1)
else
var/turf/user_loc = user.loc
var/turf/H_loc = H.loc
user.visible_message("<span class='danger'>[user] tries to shave [H]'s facial hair with \the [src].</span>", \
"<span class='warning'>You start shaving [H]'s facial hair.</span>")
if(do_after(user, 50 * toolspeed, target = H))
if(user_loc == user.loc && H_loc == H.loc)
user.visible_message("<span class='danger'>[user] shaves off [H]'s facial hair with \the [src].</span>", \
"<span class='notice'>You shave [H]'s facial hair clean off.</span>")
C.f_style = "Shaved"
H.update_fhair()
playsound(src.loc, usesound, 20, 1)
if(user.zone_selected == "head")
if(!get_location_accessible(H, "head"))
to_chat(user, "<span class='warning'>The headgear is in the way.</span>")
return
if((C.dna.species.bodyflags & ALL_RPARTS) && robohead.is_monitor) //If the target is of a species that can have prosthetic heads, but the head doesn't support human hair 'wigs'...
to_chat(user, "<span class='warning'>You find yourself disappointed at the appalling lack of hair.</span>")
return
if(C.h_style == "Bald" || C.h_style == "Balding Hair" || C.h_style == "Skinhead")
to_chat(user, "<span class='notice'>There is not enough hair left to shave...</span>")
return
if(isskrell(M))
to_chat(user, "<span class='warning'>Your razor isn't going to cut through tentacles.</span>")
return
if(H == user) //shaving yourself
user.visible_message("<span class='warning'>[user] starts to shave [user.p_their()] head with [src].</span>", \
"<span class='warning'>You start to shave your head with \the [src].</span>")
if(do_after(user, 50 * toolspeed, target = H))
user.visible_message("<span class='notice'>[user] shaves [user.p_their()] head with [src].</span>", \
"<span class='notice'>You finish shaving with \the [src].</span>")
C.h_style = "Skinhead"
H.update_hair()
playsound(src.loc, usesound, 40, 1)
else
var/turf/user_loc = user.loc
var/turf/H_loc = H.loc
user.visible_message("<span class='danger'>[user] tries to shave [H]'s head with \the [src]!</span>", \
"<span class='warning'>You start shaving [H]'s head.</span>")
if(do_after(user, 50 * toolspeed, target = H))
if(user_loc == user.loc && H_loc == H.loc)
user.visible_message("<span class='danger'>[user] shaves [H]'s head bald with \the [src]!</span>", \
"<span class='warning'>You shave [H]'s head bald.</span>")
C.h_style = "Skinhead"
H.update_hair()
playsound(src.loc, usesound, 40, 1)
else
..()
else
..()
@@ -1,36 +0,0 @@
// Contains:
// Gavel Hammer
// Gavel Block
/obj/item/gavelhammer
name = "gavel hammer"
desc = "Order, order! No bombs in my courthouse."
icon_state = "gavelhammer"
force = 5.0
throwforce = 6.0
w_class = WEIGHT_CLASS_SMALL
attack_verb = list("bashed", "battered", "judged", "whacked")
resistance_flags = FLAMMABLE
/obj/item/gavelhammer/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] has sentenced [user.p_themselves()] to death with [src]! It looks like [user.p_theyre()] trying to commit suicide!</span>")
playsound(loc, 'sound/items/gavel.ogg', 50, TRUE, -1)
return BRUTELOSS
/obj/item/gavelblock
name = "gavel block"
desc = "Smack it with a gavel hammer when the assistants get rowdy."
icon_state = "gavelblock"
force = 2.0
throwforce = 2.0
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
var/next_gavel_hit
/obj/item/gavelblock/attackby__legacy__attackchain(obj/item/I, mob/user, params)
if(!istype(I, /obj/item/gavelhammer))
return
if(world.time > next_gavel_hit)
playsound(loc, 'sound/items/gavel.ogg', 100, 1)
next_gavel_hit = world.time + 5 SECONDS
user.visible_message("<span class='warning'>[user] strikes \the [src] with \the [I].</span>")
-461
View File
@@ -1,461 +0,0 @@
//backpack item
/obj/item/defibrillator
name = "defibrillator"
desc = "A device that delivers powerful shocks to detachable paddles that resuscitate incapacitated patients."
icon = 'icons/obj/defib.dmi'
icon_state = "defibunit"
item_state = "defibunit"
slot_flags = ITEM_SLOT_BACK
force = 5
throwforce = 6
w_class = WEIGHT_CLASS_BULKY
origin_tech = "biotech=4"
actions_types = list(/datum/action/item_action/toggle_paddles)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 50, ACID = 50)
sprite_sheets = list(
"Vox" = 'icons/mob/clothing/species/vox/back.dmi'
)
/// If the paddles are currently attached to the unit.
var/paddles_on_defib = TRUE
/// if there's a cell in the defib with enough power for a revive; blocks paddles from reviving otherwise
var/powered = FALSE
/// Ref to attached paddles
var/obj/item/shockpaddles/paddles
/// Ref to internal power cell.
var/obj/item/stock_parts/cell/high/cell = null
/// If false, using harm intent will let you zap people. Note that any updates to this after init will only impact icons.
var/safety = TRUE
/// If true, this can be used through hardsuits, and can cause heart attacks in harm intent.
var/combat = FALSE
// If safety is false and combat is true, the chance that this will cause a heart attack.
var/heart_attack_probability = 30
/// If this is vulnerable to EMPs.
var/hardened = FALSE
/// If this can be emagged.
var/emag_proof = FALSE
base_icon_state = "defibpaddles"
/// Type of paddles that should be attached to this defib.
var/obj/item/shockpaddles/paddle_type = /obj/item/shockpaddles
/obj/item/defibrillator/get_cell()
return cell
/obj/item/defibrillator/Initialize(mapload) // Base version starts without a cell for rnd
. = ..()
paddles = new paddle_type(src)
update_icon(UPDATE_OVERLAYS)
/obj/item/defibrillator/loaded/Initialize(mapload) // Loaded version starts with high-capacity cell.
. = ..()
cell = new(src)
update_icon(UPDATE_OVERLAYS)
/obj/item/defibrillator/update_icon(updates=ALL)
update_power()
..()
/obj/item/defibrillator/examine(mob/user)
. = ..()
. += "<span class='notice'><b>Alt-Click</b> to remove the paddles from the defibrillator.</span>"
/obj/item/defibrillator/proc/update_power()
if(cell)
if(cell.charge < paddles.revivecost)
powered = FALSE
else
powered = TRUE
else
powered = FALSE
/obj/item/defibrillator/update_overlays()
. = ..()
if(paddles_on_defib)
. += "[icon_state]-paddles"
if(!safety)
. += "[icon_state]-emagged"
if(powered)
. += "[icon_state]-powered"
if(powered && cell)
var/ratio = cell.charge / cell.maxcharge
ratio = CEILING(ratio*4, 1) * 25
. += "[icon_state]-charge[ratio]"
if(!cell)
. += "[icon_state]-nocell"
/obj/item/defibrillator/CheckParts(list/parts_list)
..()
cell = locate(/obj/item/stock_parts/cell) in contents
update_icon(UPDATE_OVERLAYS)
/obj/item/defibrillator/ui_action_click(mob/user)
toggle_paddles(user)
/obj/item/defibrillator/AltClick(mob/user)
if(ishuman(user) && Adjacent(user))
toggle_paddles(user)
/obj/item/defibrillator/attackby__legacy__attackchain(obj/item/W, mob/user, params)
if(istype(W, /obj/item/stock_parts/cell))
var/obj/item/stock_parts/cell/C = W
if(cell)
to_chat(user, "<span class='notice'>[src] already has a cell.</span>")
else
if(C.maxcharge < paddles.revivecost)
to_chat(user, "<span class='notice'>[src] requires a higher capacity cell.</span>")
return
if(user.drop_item(C))
W.forceMove(src)
cell = C
to_chat(user, "<span class='notice'>You install a cell in [src].</span>")
if(W == paddles)
toggle_paddles(user)
update_icon(UPDATE_OVERLAYS)
/obj/item/defibrillator/screwdriver_act(mob/living/user, obj/item/I)
if(!cell)
to_chat(user, "<span class='notice'>[src] doesn't have a cell.</span>")
return
cell.update_icon()
cell.forceMove(get_turf(loc))
cell = null
to_chat(user, "<span class='notice'>You remove the cell from [src].</span>")
update_icon(UPDATE_OVERLAYS)
return TRUE
/obj/item/defibrillator/emp_act(severity)
if(cell)
deductcharge(1000 / severity)
safety = !safety
update_icon(UPDATE_OVERLAYS)
..()
/obj/item/defibrillator/emag_act(mob/user)
safety = !safety
..()
update_icon(UPDATE_OVERLAYS)
return TRUE
/obj/item/defibrillator/proc/toggle_paddles(mob/living/carbon/human/user)
if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user))
return
if(paddles_on_defib)
//Detach the paddles into the user's hands
if(!user.put_in_hands(paddles))
to_chat(user, "<span class='warning'>You need a free hand to hold the paddles!</span>")
update_icon(UPDATE_OVERLAYS)
return
paddles.forceMove(user)
paddles_on_defib = FALSE
else if(user.is_in_active_hand(paddles))
//Remove from their hands and back onto the defib unit
remove_paddles(user)
update_icon(UPDATE_OVERLAYS)
update_action_buttons()
/obj/item/defibrillator/equipped(mob/user, slot)
..()
if(slot != ITEM_SLOT_BACK)
remove_paddles(user)
update_icon(UPDATE_OVERLAYS)
/obj/item/defibrillator/on_mob_move(dir, mob/user)
if(paddles_on_defib)
return
if(paddles.loc != user)
remove_paddles(paddles.loc)
/obj/item/defibrillator/item_action_slot_check(slot, mob/user)
if(slot == ITEM_SLOT_BACK)
return TRUE
/obj/item/defibrillator/proc/remove_paddles(mob/user) // from your hands
var/mob/living/carbon/human/M = user
if(paddles in get_both_hands(M))
M.drop_item_to_ground(paddles)
paddles_on_defib = TRUE
update_icon(UPDATE_OVERLAYS)
return
/obj/item/defibrillator/Destroy()
if(!paddles_on_defib)
var/M = get(paddles, /mob)
remove_paddles(M)
QDEL_NULL(paddles)
QDEL_NULL(cell)
return ..()
/obj/item/defibrillator/proc/deductcharge(chrgdeductamt)
if(cell)
if(cell.charge < (paddles.revivecost+chrgdeductamt))
powered = FALSE
update_icon(UPDATE_OVERLAYS)
if(cell.use(chrgdeductamt))
update_icon(UPDATE_OVERLAYS)
return TRUE
else
update_icon(UPDATE_OVERLAYS)
return FALSE
/obj/item/defibrillator/compact
name = "compact defibrillator"
desc = "A belt-mounted defibrillator that can be rapidly deployed."
icon_state = "defibcompact"
item_state = "defibcompact"
sprite_sheets = null //Because Vox had the belt defibrillator sprites in back.dm
w_class = WEIGHT_CLASS_NORMAL
slot_flags = ITEM_SLOT_BELT
flags_2 = ALLOW_BELT_NO_JUMPSUIT_2
origin_tech = "biotech=5"
/obj/item/defibrillator/compact/loaded/Initialize(mapload)
. = ..()
cell = new(src)
update_icon(UPDATE_OVERLAYS)
/obj/item/defibrillator/compact/item_action_slot_check(slot, mob/user)
if(slot == ITEM_SLOT_BELT)
return TRUE
/obj/item/defibrillator/compact/combat
name = "combat defibrillator"
desc = "A belt-mounted blood-red defibrillator that can be rapidly deployed. Does not have the restrictions or safeties of conventional defibrillators and can revive through space suits."
icon_state = "defibcombat"
item_state = "defibcombat"
paddle_type = /obj/item/shockpaddles/syndicate
combat = TRUE
safety = FALSE
heart_attack_probability = 100
/obj/item/defibrillator/compact/combat/loaded/Initialize(mapload)
. = ..()
cell = new(src)
update_icon(UPDATE_OVERLAYS)
/obj/item/defibrillator/compact/advanced
name = "advanced compact defibrillator"
desc = "A belt-mounted state-of-the-art defibrillator that can be rapidly deployed in all environments. The casing is EMP-shielded and heavily reinforced, making it immune to most sources of damage."
icon_state = "defibnt"
item_state = "defibnt"
paddle_type = /obj/item/shockpaddles/advanced
combat = TRUE
hardened = TRUE // EMP-proof (on the component), but not emag-proof.
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF // Objective item, better not have it destroyed.
heart_attack_probability = 10
origin_tech = null
/// To prevent spam from the emagging message on the advanced defibrillator.
var/next_emp_message
/obj/item/defibrillator/compact/advanced/examine(mob/user)
. = ..()
. += "<span class='notice'>[src] uses an experimental self-charging cell, meaning that it will (probably) never stop working.</span>"
. += "<span class='notice'>The advanced paddles can be used to defibrillate through space suits.</span>"
/obj/item/defibrillator/compact/advanced/examine_more(mob/user)
. = ..()
. += "The Advanced Compact Defibrillator is Nanotrasen Medical's greatest refinement of electroshock revival technology. Featuring heavy electromagnetic shielding and a reinforced plastitanium chassis, \
it is both lightweight and extremely resistant to abuse, easily able to handle the most hostile of environments."
. += ""
. += "The two standout features of the ACD are the experimental self-charging power source - which gives it an effectively unlimited endurance - and the special breakdown paddles, \
capable of transmitting a therapeutic shock through even thick hardsuit plating, allowing casualties to be revived without having to strip their equipment."
. += ""
. += "Whilst the ACD is currently too expensive for mass-market deployment, Nanotrasen hopes that later developments in its manufacturing capabilities will enable it to economically launch this product commercially."
/obj/item/defibrillator/compact/advanced/screwdriver_act(mob/living/user, obj/item/I)
return // The cell is too strong roundstart and we dont want the adv defib to become useless
/obj/item/defibrillator/compact/advanced/loaded/Initialize(mapload)
. = ..()
cell = new /obj/item/stock_parts/cell/bluespace/charging(src)
update_icon(UPDATE_OVERLAYS)
AddElement(/datum/element/high_value_item)
/obj/item/defibrillator/compact/advanced/emp_act(severity)
if(world.time > next_emp_message)
atom_say("Warning: Electromagnetic pulse detected. Integrated shielding prevented all potential hardware damage.")
playsound(src, 'sound/machines/defib_saftyon.ogg', 50)
next_emp_message = world.time + 5 SECONDS
//paddles
/obj/item/shockpaddles
name = "defibrillator paddles"
desc = "A pair of plastic-gripped paddles with flat metal surfaces that are used to deliver powerful electric shocks."
icon = 'icons/obj/defib.dmi'
icon_state = "defibpaddles0"
item_state = "defibpaddles0"
throwforce = 6
w_class = WEIGHT_CLASS_BULKY
resistance_flags = INDESTRUCTIBLE
base_icon_state = "defibpaddles"
/// Amount of power used on a shock.
var/revivecost = 1000
/// Active defib this is connected to.
var/obj/item/defibrillator/defib
/// Whether or not the paddles are on cooldown. Used for tracking icon states.
var/on_cooldown = FALSE
/obj/item/shockpaddles/New(mainunit)
. = ..()
if(check_defib_exists(mainunit, null, src))
defib = mainunit
loc = defib
update_icon(UPDATE_ICON_STATE)
AddComponent(/datum/component/defib, actual_unit = defib, combat = defib.combat, safe_by_default = defib.safety, heart_attack_chance = defib.heart_attack_probability, emp_proof = defib.hardened, emag_proof = defib.emag_proof)
else
AddComponent(/datum/component/defib)
RegisterSignal(src, COMSIG_DEFIB_READY, PROC_REF(on_cooldown_expire))
RegisterSignal(src, COMSIG_DEFIB_SHOCK_APPLIED, PROC_REF(after_shock))
RegisterSignal(src, COMSIG_DEFIB_PADDLES_APPLIED, PROC_REF(on_application))
AddComponent(/datum/component/two_handed)
/obj/item/shockpaddles/Destroy()
defib = null
return ..()
/// Check to see if we should abort this before we've even gotten started
/obj/item/shockpaddles/proc/on_application(obj/item/paddles, mob/living/user, mob/living/carbon/human/target, should_cause_harm)
SIGNAL_HANDLER // COMSIG_DEFIB_PADDLES_APPLIED
if(!HAS_TRAIT(src, TRAIT_WIELDED))
to_chat(user, "<span class='boldnotice'>You need to wield the paddles in both hands before you can use them on someone!</span>")
return COMPONENT_BLOCK_DEFIB_MISC
if(!defib.powered)
return COMPONENT_BLOCK_DEFIB_DEAD
return
/obj/item/shockpaddles/proc/on_cooldown_expire(obj/item/paddles)
SIGNAL_HANDLER // COMSIG_DEFIB_READY
on_cooldown = FALSE
if(defib.cell)
if(defib.cell.charge >= revivecost)
defib.visible_message("<span class='notice'>[defib] beeps: Unit ready.</span>")
playsound(get_turf(src), 'sound/machines/defib_ready.ogg', 50, 0)
else
defib.visible_message("<span class='notice'>[defib] beeps: Charge depleted.</span>")
playsound(get_turf(src), 'sound/machines/defib_failed.ogg', 50, 0)
update_icon(UPDATE_ICON_STATE)
defib.update_icon(UPDATE_ICON_STATE)
/obj/item/shockpaddles/proc/after_shock()
SIGNAL_HANDLER // COMSIG_DEFIB_SHOCK_APPLIED
on_cooldown = TRUE
defib.deductcharge(revivecost)
update_icon(UPDATE_ICON_STATE)
/obj/item/shockpaddles/update_icon_state()
var/wielded = HAS_TRAIT(src, TRAIT_WIELDED)
icon_state = "[base_icon_state][wielded]"
item_state = "[base_icon_state][wielded]"
if(on_cooldown)
icon_state = "[base_icon_state][wielded]_cooldown"
/obj/item/shockpaddles/suicide_act(mob/user)
user.visible_message("<span class='danger'>[user] is putting the live paddles on [user.p_their()] chest! It looks like [user.p_theyre()] trying to commit suicide!</span>")
defib.deductcharge(revivecost)
playsound(get_turf(src), 'sound/machines/defib_zap.ogg', 50, TRUE, -1)
return OXYLOSS
/obj/item/shockpaddles/dropped(mob/user)
..()
if(user)
to_chat(user, "<span class='notice'>The paddles snap back into the main unit.</span>")
defib.paddles_on_defib = TRUE
loc = defib
defib.update_icon(UPDATE_OVERLAYS)
update_icon(UPDATE_ICON_STATE)
/obj/item/shockpaddles/on_give(mob/living/carbon/giver, mob/living/carbon/receiver)
// This should be True, because action give calls drop() before this proc
if(defib.paddles_on_defib)
//Detach the paddles into the user's hands
defib.paddles.forceMove(receiver)
defib.paddles_on_defib = FALSE
else if(receiver.is_in_active_hand(defib.paddles))
//Remove from their hands and back onto the defib unit
defib.remove_paddles(receiver)
defib.update_icon(UPDATE_OVERLAYS)
update_icon(UPDATE_ICON_STATE)
// We call this to check if the receiver is outside the defib range
// Otherwise, it can be placed anywhere on the map
on_mob_move(null, receiver)
/obj/item/shockpaddles/on_mob_move(dir, mob/user)
if(defib)
if(!isturf(user.loc))
// You went inside something. It blocks the cable.
// (This also means we don't have to listen for the
// surrounding object's movements.)
defib.remove_paddles(user)
var/turf/t = get_turf(defib)
if(!t.Adjacent(user))
defib.remove_paddles(user)
/obj/item/shockpaddles/proc/check_defib_exists(mainunit, mob/living/carbon/human/M, obj/O)
if(!mainunit || !istype(mainunit, /obj/item/defibrillator)) //To avoid weird issues from admin spawns
M?.unequip(O)
qdel(O)
return FALSE
else
return TRUE
/obj/item/borg_defib
name = "defibrillator paddles"
desc = "A pair of paddles with flat metal surfaces that are used to deliver powerful electric shocks."
icon = 'icons/obj/defib.dmi'
icon_state = "defibpaddles0"
item_state = "defibpaddles0"
w_class = WEIGHT_CLASS_BULKY
var/revivecost = 1000
var/safety = TRUE
flags = NODROP
/obj/item/borg_defib/Initialize(mapload)
. = ..()
AddComponent(/datum/component/defib, robotic = TRUE, safe_by_default = safety, emp_proof = TRUE)
RegisterSignal(src, COMSIG_DEFIB_READY, PROC_REF(on_cooldown_expire))
RegisterSignal(src, COMSIG_DEFIB_SHOCK_APPLIED, PROC_REF(after_shock))
/obj/item/borg_defib/proc/after_shock(obj/item/defib, mob/user)
SIGNAL_HANDLER // COMSIG_DEFIB_SHOCK_APPLIED
if(isrobot(user))
var/mob/living/silicon/robot/R = user
R.cell.use(revivecost)
update_icon(UPDATE_ICON_STATE)
/obj/item/borg_defib/proc/on_cooldown_expire(obj/item/defib)
SIGNAL_HANDLER // COMSIG_DEFIB_READY
visible_message("<span class='notice'>[src] beeps: Defibrillation unit ready.</span>")
playsound(get_turf(src), 'sound/machines/defib_ready.ogg', 50, 0)
update_icon(UPDATE_ICON_STATE)
/obj/item/shockpaddles/syndicate
name = "combat defibrillator paddles"
desc = "A pair of high-tech paddles with flat plasteel surfaces to revive deceased operatives (unless they exploded). They possess both the ability to penetrate armor and to deliver powerful or disabling shocks offensively."
icon_state = "syndiepaddles0"
item_state = "syndiepaddles0"
base_icon_state = "syndiepaddles"
/obj/item/shockpaddles/advanced
name = "advanced defibrillator paddles"
desc = "A pair of high-tech paddles with flat plasteel surfaces that are used to deliver powerful electric shocks. They possess the ability to penetrate armor to deliver shock."
icon_state = "ntpaddles0"
item_state = "ntpaddles0"
base_icon_state = "ntpaddles"
-73
View File
@@ -1,73 +0,0 @@
/obj/item/disk
icon = 'icons/obj/module.dmi'
w_class = WEIGHT_CLASS_TINY
item_state = "card-id"
icon_state = "datadisk0"
drop_sound = 'sound/items/handling/disk_drop.ogg'
pickup_sound = 'sound/items/handling/disk_pickup.ogg'
/obj/item/disk/data
name = "Cloning Data Disk"
var/datum/dna2_record/buf = null
var/read_only = FALSE //Well,it's still a floppy disk
/obj/item/disk/data/proc/initialize_data()
buf = new
buf.dna = new
/obj/item/disk/data/Destroy()
QDEL_NULL(buf)
return ..()
/obj/item/disk/data/demo
name = "data disk - 'God Emperor of Mankind'"
read_only = TRUE
/obj/item/disk/data/demo/New()
. = ..()
initialize_data()
buf.types = DNA2_BUF_UE|DNA2_BUF_UI
buf.dna.real_name = "God Emperor of Mankind"
buf.dna.unique_enzymes = md5(buf.dna.real_name)
buf.dna.UI = list(0x066,0x000,0x033,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0xAF0,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x033,0x066,0x0FF,0x4DB,0x002,0x690,0x000,0x000,0x000,0x328,0x045,0x5FC,0x053,0x035,0x035,0x035)
if(length(buf.dna.UI) != DNA_UI_LENGTH) //If there's a disparity b/w the dna UI string lengths, 0-fill the extra blocks in this UI.
for(var/i in length(buf.dna.UI) to DNA_UI_LENGTH)
buf.dna.UI += 0x000
buf.dna.ResetSE()
buf.dna.UpdateUI()
/obj/item/disk/data/monkey
name = "data disk - 'Mr. Muggles'"
read_only = 1
/obj/item/disk/data/monkey/New()
. = ..()
initialize_data()
buf.types = DNA2_BUF_SE
var/list/new_SE = list(0x098,0x3E8,0x403,0x44C,0x39F,0x4B0,0x59D,0x514,0x5FC,0x578,0x5DC,0x640,0x6A4)
for(var/i = length(new_SE); i <= DNA_SE_LENGTH; i++)
new_SE += rand(1, 1024)
buf.dna.SE = new_SE
buf.dna.SetSEValueRange(GLOB.monkeyblock, 0xDAC, 0xFFF)
//Disk stuff.
/obj/item/disk/data/New()
. = ..()
var/diskcolor = pick(0, 1, 2, 3, 4, 5)
icon_state = "datadisk[diskcolor]"
/obj/item/disk/data/attack_self__legacy__attackchain(mob/user)
read_only = !read_only
to_chat(user, "You flip the write-protect tab to [read_only ? "protected" : "unprotected"].")
/obj/item/disk/data/examine(mob/user)
. = ..()
. += "The write-protect tab is set to [read_only ? "protected" : "unprotected"]."
/obj/item/storage/box/disks
name = "Diskette Box"
icon_state = "disk_box"
/obj/item/storage/box/disks/populate_contents()
for(var/i in 1 to 7)
new /obj/item/disk/data(src)
@@ -1,607 +0,0 @@
/obj/item/dnainjector
name = "DNA-Injector"
desc = "This injects the person with DNA."
icon = 'icons/obj/medical.dmi'
icon_state = "dnainjector"
item_state = "dnainjector"
belt_icon = "syringe"
var/block = 0
var/datum/dna2_record/buf = null
throw_speed = 3
throw_range = 5
w_class = WEIGHT_CLASS_TINY
origin_tech = "biotech=1"
var/damage_coeff = 1
var/used = FALSE
// USE ONLY IN PREMADE SYRINGES. WILL NOT WORK OTHERWISE.
var/datatype = 0
var/value = 0
var/forcedmutation = FALSE //Will it give the mutation, guaranteed?
/obj/item/dnainjector/Initialize(mapload)
. = ..()
var/init_block = GetInitBlock()
if(init_block)
block = init_block
if(datatype && block)
buf = new
buf.dna = new
buf.types = datatype
buf.dna.ResetSE()
SetValue(value)
// Override this with a var reference to do setup
/obj/item/dnainjector/proc/GetInitBlock()
return null
/obj/item/dnainjector/Destroy()
QDEL_NULL(buf)
return ..()
/obj/item/dnainjector/proc/GetRealBlock(selblock)
if(selblock == 0)
return block
else
return selblock
/obj/item/dnainjector/proc/GetState(selblock = 0)
var/real_block = GetRealBlock(selblock)
if(buf.types & DNA2_BUF_SE)
return buf.dna.GetSEState(real_block)
else
return buf.dna.GetUIState(real_block)
/obj/item/dnainjector/proc/SetState(on, selblock = 0)
var/real_block = GetRealBlock(selblock)
if(buf.types & DNA2_BUF_SE)
return buf.dna.SetSEState(real_block,on)
else
return buf.dna.SetUIState(real_block,on)
/obj/item/dnainjector/proc/GetValue(selblock = 0)
var/real_block = GetRealBlock(selblock)
if(buf.types & DNA2_BUF_SE)
return buf.dna.GetSEValue(real_block)
else
return buf.dna.GetUIValue(real_block)
/obj/item/dnainjector/proc/SetValue(val, selblock = 0)
var/real_block = GetRealBlock(selblock)
if(buf.types & DNA2_BUF_SE)
return buf.dna.SetSEValue(real_block,val)
else
return buf.dna.SetUIValue(real_block,val)
/obj/item/dnainjector/proc/inject(mob/living/M, mob/user)
if(used)
return
if(isliving(M))
M.apply_effect(rand(20 / (damage_coeff ** 2), 50 / (damage_coeff ** 2)), IRRADIATE)
var/mob/living/carbon/human/H
if(ishuman(M))
H = M
if(!buf)
stack_trace("[src] used by [user] on [M] failed to initialize properly.")
return
spawn(0) //Some mutations have sleeps in them, like monkey
if(!HAS_TRAIT(M, TRAIT_BADDNA) && !HAS_TRAIT(M, TRAIT_GENELESS)) // prevents drained people from having their DNA changed
var/prev_ue = M.dna.unique_enzymes
// UI in syringe.
if(buf.types & DNA2_BUF_UI)
if(!block) //isolated block?
M.dna.UI = buf.dna.UI.Copy()
M.dna.UpdateUI()
M.UpdateAppearance()
if(buf.types & DNA2_BUF_UE) //unique enzymes? yes
M.real_name = buf.dna.real_name
M.name = buf.dna.real_name
M.dna.real_name = buf.dna.real_name
M.dna.unique_enzymes = buf.dna.unique_enzymes
else
M.dna.SetUIValue(block,src.GetValue())
M.UpdateAppearance()
if(buf.types & DNA2_BUF_SE)
if(!block) //isolated block?
M.dna.SE = buf.dna.SE.Copy()
M.dna.UpdateSE()
else
M.dna.SetSEValue(block,src.GetValue())
domutcheck(M, forcedmutation ? MUTCHK_FORCED : FALSE)
M.update_mutations()
if(H)
H.sync_organ_dna(assimilate = 0, old_ue = prev_ue)
/obj/item/dnainjector/attack__legacy__attackchain(mob/M, mob/user)
if(used)
to_chat(user, "<span class='warning'>This injector is used up!</span>")
return
if(!M.dna || HAS_TRAIT(M, TRAIT_GENELESS) || HAS_TRAIT(M, TRAIT_BADDNA)) //You know what would be nice? If the mob you're injecting has DNA, and so doesn't cause runtimes.
return FALSE
if(!user.IsAdvancedToolUser())
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return FALSE
var/attack_log = "injected with the Isolated [name]"
if(buf && buf.types & DNA2_BUF_SE)
if(block)
if(GetState() && block == GLOB.monkeyblock && ishuman(M))
attack_log = "injected with the Isolated [name] (MONKEY)"
message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] <span class='warning'>(MONKEY)</span>")
else
if(GetState(GLOB.monkeyblock) && ishuman(M))
attack_log = "injected with the Isolated [name] (MONKEY)"
message_admins("[key_name_admin(user)] injected [key_name_admin(M)] with the Isolated [name] <span class='warning'>(MONKEY)</span>")
if(M != user)
M.visible_message("<span class='danger'>[user] is trying to inject [M] with [src]!</span>", "<span class='userdanger'>[user] is trying to inject [M] with [src]!</span>")
if(!do_mob(user, M))
return
M.visible_message("<span class='danger'>[user] injects [M] with the syringe with [src]!", \
"<span class='userdanger'>[user] injects [M] with the syringe with [src]!")
else
to_chat(user, "<span class='notice'>You inject yourself with [src].</span>")
add_attack_logs(user, M, attack_log, ATKLOG_ALL)
inject(M, user)
used = TRUE
icon_state = "dnainjector0"
desc += " This one is used up."
/obj/item/dnainjector/hulkmut
name = "DNA-Injector (Hulk)"
desc = "This will make you big and strong, but give you a bad skin condition."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/hulkmut/GetInitBlock()
return GLOB.hulkblock
/obj/item/dnainjector/antihulk
name = "DNA-Injector (Anti-Hulk)"
desc = "Cures green skin."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antihulk/GetInitBlock()
return GLOB.hulkblock
/obj/item/dnainjector/firemut
name = "DNA-Injector (Fire)"
desc = "Gives you fire."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/firemut/GetInitBlock()
return GLOB.fireblock
/obj/item/dnainjector/antifire
name = "DNA-Injector (Anti-Fire)"
desc = "Cures fire."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antifire/GetInitBlock()
return GLOB.fireblock
/obj/item/dnainjector/telemut
name = "DNA-Injector (Tele.)"
desc = "Super brain man!"
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/telemut/GetInitBlock()
return GLOB.teleblock
/obj/item/dnainjector/telemut/darkbundle
name = "DNA injector"
desc = "Good. Let the hate flow through you."
/obj/item/dnainjector/antitele
name = "DNA-Injector (Anti-Tele.)"
desc = "Will make you not able to control your mind."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antitele/GetInitBlock()
return GLOB.teleblock
/obj/item/dnainjector/nobreath
name = "DNA-Injector (Breathless)"
desc = "Hold your breath and count to infinity."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/nobreath/GetInitBlock()
return GLOB.breathlessblock
/obj/item/dnainjector/antinobreath
name = "DNA-Injector (Anti-Breathless)"
desc = "Hold your breath and count to 100."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antinobreath/GetInitBlock()
return GLOB.breathlessblock
/obj/item/dnainjector/remoteview
name = "DNA-Injector (Remote View)"
desc = "Stare into the distance for a reason."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/remoteview/GetInitBlock()
return GLOB.remoteviewblock
/obj/item/dnainjector/antiremoteview
name = "DNA-Injector (Anti-Remote View)"
desc = "Cures green skin."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antiremoteview/GetInitBlock()
return GLOB.remoteviewblock
/obj/item/dnainjector/regenerate
name = "DNA-Injector (Regeneration)"
desc = "Healthy but hungry."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/regenerate/GetInitBlock()
return GLOB.regenerateblock
/obj/item/dnainjector/antiregenerate
name = "DNA-Injector (Anti-Regeneration)"
desc = "Sickly but sated."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antiregenerate/GetInitBlock()
return GLOB.regenerateblock
/obj/item/dnainjector/morph
name = "DNA-Injector (Morph)"
desc = "A total makeover."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/morph/GetInitBlock()
return GLOB.morphblock
/obj/item/dnainjector/antimorph
name = "DNA-Injector (Anti-Morph)"
desc = "Cures identity crisis."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antimorph/GetInitBlock()
return GLOB.morphblock
/obj/item/dnainjector/noprints
name = "DNA-Injector (No Prints)"
desc = "Better than a pair of budget insulated gloves."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/noprints/GetInitBlock()
return GLOB.noprintsblock
/obj/item/dnainjector/antinoprints
name = "DNA-Injector (Anti-No Prints)"
desc = "Not quite as good as a pair of budget insulated gloves."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antinoprints/GetInitBlock()
return GLOB.noprintsblock
/obj/item/dnainjector/insulation
name = "DNA-Injector (Shock Immunity)"
desc = "Better than a pair of real insulated gloves."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/insulation/GetInitBlock()
return GLOB.shockimmunityblock
/obj/item/dnainjector/antiinsulation
name = "DNA-Injector (Anti-Shock Immunity)"
desc = "Not quite as good as a pair of real insulated gloves."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antiinsulation/GetInitBlock()
return GLOB.shockimmunityblock
/obj/item/dnainjector/small_size
name = "DNA-Injector (Small Size)"
desc = "Makes you shrink."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/small_size/GetInitBlock()
return GLOB.smallsizeblock
/obj/item/dnainjector/anti_small_size
name = "DNA-Injector (Anti-Small Size)"
desc = "Makes you grow. But not too much."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/anti_small_size/GetInitBlock()
return GLOB.smallsizeblock
/obj/item/dnainjector/eatmut
name = "DNA-Injector (Matter Eater)"
desc = "Gives you an appetite for anything."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/eatmut/GetInitBlock()
return GLOB.eatblock
/obj/item/dnainjector/antieat
name = "DNA-Injector (Anti-Matter Eater)"
desc = "Makes you regain your normal appetite."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antieat/GetInitBlock()
return GLOB.eatblock
/////////////////////////////////////
/obj/item/dnainjector/antiglasses
name = "DNA-Injector (Anti-Glasses)"
desc = "Toss away those glasses!"
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antiglasses/GetInitBlock()
return GLOB.glassesblock
/obj/item/dnainjector/glassesmut
name = "DNA-Injector (Glasses)"
desc = "Will make you need dorkish glasses."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/glassesmut/GetInitBlock()
return GLOB.glassesblock
/obj/item/dnainjector/epimut
name = "DNA-Injector (Epi.)"
desc = "Shake shake shake the room!"
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/epimut/GetInitBlock()
return GLOB.epilepsyblock
/obj/item/dnainjector/antiepi
name = "DNA-Injector (Anti-Epi.)"
desc = "Will fix you up from shaking the room."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antiepi/GetInitBlock()
return GLOB.epilepsyblock
/obj/item/dnainjector/anticough
name = "DNA-Injector (Anti-Cough)"
desc = "Will stop that awful noise."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/anticough/GetInitBlock()
return GLOB.coughblock
/obj/item/dnainjector/coughmut
name = "DNA-Injector (Cough)"
desc = "Will bring forth a sound of horror from your throat."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/coughmut/GetInitBlock()
return GLOB.coughblock
/obj/item/dnainjector/clumsymut
name = "DNA-Injector (Clumsy)"
desc = "Makes clumsy minions."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/clumsymut/GetInitBlock()
return GLOB.clumsyblock
/obj/item/dnainjector/anticlumsy
name = "DNA-Injector (Anti-Clumy)"
desc = "Cleans up confusion."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/anticlumsy/GetInitBlock()
return GLOB.clumsyblock
/obj/item/dnainjector/stuttmut
name = "DNA-Injector (Stutt.)"
desc = "Makes you s-s-stuttterrr."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/stuttmut/GetInitBlock()
return GLOB.nervousblock
/obj/item/dnainjector/antistutt
name = "DNA-Injector (Anti-Stutt.)"
desc = "Fixes that speaking impairment."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antistutt/GetInitBlock()
return GLOB.nervousblock
/obj/item/dnainjector/blindmut
name = "DNA-Injector (Blind)"
desc = "Makes you not see anything."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/blindmut/GetInitBlock()
return GLOB.blindblock
/obj/item/dnainjector/antiblind
name = "DNA-Injector (Anti-Blind)"
desc = "ITS A MIRACLE!!!"
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antiblind/GetInitBlock()
return GLOB.blindblock
/obj/item/dnainjector/paraplegicmut
name = "DNA-Injector (Paraplegic)"
desc = "Faceplanting, in needle form."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/paraplegicmut/GetInitBlock()
return GLOB.paraplegicblock
/obj/item/dnainjector/antiparaplegic
name = "DNA-Injector (Anti-Paraplegic)"
desc = "Returns your legs to working order."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antiparaplegic/GetInitBlock()
return GLOB.paraplegicblock
/obj/item/dnainjector/deafmut
name = "DNA-Injector (Deaf)"
desc = "Sorry, what did you say?"
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/deafmut/GetInitBlock()
return GLOB.deafblock
/obj/item/dnainjector/antideaf
name = "DNA-Injector (Anti-Deaf)"
desc = "Will make you hear once more."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antideaf/GetInitBlock()
return GLOB.deafblock
/obj/item/dnainjector/hallucination
name = "DNA-Injector (Halluctination)"
desc = "What you see isn't always what you get."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/hallucination/GetInitBlock()
return GLOB.hallucinationblock
/obj/item/dnainjector/antihallucination
name = "DNA-Injector (Anti-Hallucination)"
desc = "What you see is what you get."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/antihallucination/GetInitBlock()
return GLOB.hallucinationblock
/obj/item/dnainjector/h2m
name = "DNA-Injector (Human > Monkey)"
desc = "Will make you a flea bag."
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/h2m/GetInitBlock()
return GLOB.monkeyblock
/obj/item/dnainjector/m2h
name = "DNA-Injector (Monkey > Human)"
desc = "Will make you...less hairy."
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/m2h/GetInitBlock()
return GLOB.monkeyblock
/obj/item/dnainjector/comic
name = "DNA-Injector (Comic)"
desc = "Honk!"
datatype = DNA2_BUF_SE
value = 0xFFF
forcedmutation = TRUE
/obj/item/dnainjector/comic/GetInitBlock()
return GLOB.comicblock
/obj/item/dnainjector/anticomic
name = "DNA-Injector (Ant-Comic)"
desc = "Honk...?"
datatype = DNA2_BUF_SE
value = 0x001
forcedmutation = TRUE
/obj/item/dnainjector/anticomic/GetInitBlock()
return GLOB.comicblock
@@ -1,49 +0,0 @@
/obj/item/dnascrambler
name = "dna scrambler"
desc = "An illegal genetic serum designed to randomize the user's identity."
icon = 'icons/obj/hypo.dmi'
item_state = "syringe_0"
icon_state = "lepopen"
var/used = FALSE
/obj/item/dnascrambler/update_icon_state()
if(used)
icon_state = "lepopen0"
else
icon_state = "lepopen"
/obj/item/dnascrambler/attack__legacy__attackchain(mob/M as mob, mob/user as mob)
if(!M || !user)
return
if(!ishuman(M) || !ishuman(user))
return
if(used)
return
if(HAS_TRAIT(M, TRAIT_GENELESS))
to_chat(user, "<span class='warning'>You failed to inject [M], as [M.p_they()] [M.p_have()] no DNA to scramble, nor flesh to inject.</span>")
return
if(M == user)
user.visible_message("<span class='danger'>[user] injects [user.p_themselves()] with [src]!</span>")
injected(user, user)
else
user.visible_message("<span class='danger'>[user] is trying to inject [M] with [src]!</span>")
if(do_mob(user,M,30))
user.visible_message("<span class='danger'>[user] injects [M] with [src].</span>")
injected(M, user)
else
to_chat(user, "<span class='warning'>You failed to inject [M].</span>")
/obj/item/dnascrambler/proc/injected(mob/living/carbon/human/target, mob/living/carbon/user)
if(istype(target))
var/mob/living/carbon/human/H = target
H.get_dna_scrambled()
target.update_icons()
add_attack_logs(user, target, "injected with [src]")
used = TRUE
update_icon(UPDATE_ICON_STATE)
name = "used " + name
-434
View File
@@ -1,434 +0,0 @@
// MARK: LIGHTERS
/obj/item/lighter
name = "cheap lighter"
desc = "A cheap cigarette lighter. It gets the job done, barely."
icon = 'icons/obj/lighter.dmi'
lefthand_file = 'icons/mob/inhands/lighter_lefthand.dmi'
righthand_file = 'icons/mob/inhands/lighter_righthand.dmi'
icon_state = "lighter-g"
item_state = "lighter-g"
w_class = WEIGHT_CLASS_TINY
flags = CONDUCT
slot_flags = ITEM_SLOT_BELT
attack_verb = null
resistance_flags = FIRE_PROOF
var/lit = FALSE
/// Cooldown until the next turned on message/sound can be activated
var/next_on_message
/// Cooldown until the next turned off message/sound can be activated
var/next_off_message
/// Our lighter color suffix. => `[base_icon_state]-[lightercolor]` => `lighter-r`
var/lighter_color
var/is_a_zippo = FALSE
/obj/item/lighter/random
base_icon_state = "lighter"
/obj/item/lighter/random/Initialize(mapload)
. = ..()
lighter_color = pick("r","c","y","g")
update_icon()
/obj/item/lighter/attack_self__legacy__attackchain(mob/living/user)
. = ..()
if(!lit)
turn_on_lighter(user)
else
turn_off_lighter(user)
/obj/item/lighter/can_enter_storage(obj/item/storage/S, mob/user)
if(lit)
to_chat(user, "<span class='warning'>[S] can't hold [src] while it's lit!</span>")
return FALSE
else
return TRUE
/obj/item/lighter/proc/turn_on_lighter(mob/living/user)
lit = TRUE
w_class = WEIGHT_CLASS_BULKY
force = 5
damtype = BURN
hitsound = 'sound/items/welder.ogg'
attack_verb = list("burnt", "singed")
update_icon()
attempt_light(user)
set_light(2)
START_PROCESSING(SSobj, src)
/obj/item/lighter/proc/attempt_light(mob/living/user)
if(prob(75) || issilicon(user)) // Robots can never burn themselves trying to light it.
to_chat(user, "<span class='notice'>You light [src].</span>")
else if(HAS_TRAIT(user, TRAIT_BADASS))
to_chat(user, "<span class='notice'>[src]'s flames lick your hand as you light it, but you don't flinch.</span>")
else
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/affecting = H.get_organ("[user.hand ? "l" : "r" ]_hand")
if(affecting.receive_damage(0, 5)) //INFERNO
H.UpdateDamageIcon()
to_chat(user,"<span class='notice'>You light [src], but you burn your hand in the process.</span>")
if(world.time > next_on_message)
playsound(src, 'sound/items/lighter/plastic_strike.ogg', 25, TRUE)
next_on_message = world.time + 5 SECONDS
/obj/item/lighter/proc/turn_off_lighter(mob/living/user)
lit = FALSE
w_class = WEIGHT_CLASS_TINY
hitsound = "swing_hit"
force = 0
attack_verb = null //human_defense.dm takes care of it
damtype = initial(damtype)
update_icon()
if(user)
show_off_message(user)
set_light(0)
STOP_PROCESSING(SSobj, src)
/obj/item/lighter/extinguish_light(force)
if(!force)
return
turn_off_lighter()
/obj/item/lighter/proc/show_off_message(mob/living/user)
to_chat(user, "<span class='notice'>You shut off [src].")
if(world.time > next_off_message)
playsound(src, 'sound/items/lighter/plastic_close.ogg', 25, TRUE)
next_off_message = world.time + 5 SECONDS
/obj/item/lighter/attack__legacy__attackchain(mob/living/target, mob/living/user)
if(cigarette_lighter_act(user, target))
return
if(lit && target.IgniteMob())
message_admins("[key_name_admin(user)] set [key_name_admin(target)] on fire")
log_game("[key_name(user)] set [key_name(target)] on fire")
return ..()
/obj/item/lighter/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
var/obj/item/clothing/mask/cigarette/cig = ..()
// Otherwise the later parts of this proc can be passed to the zippo and cause a runtime.
if(is_a_zippo)
return cig
if(!cig)
return !isnull(cig)
if(!lit)
to_chat(user, "<span class='warning'>You need to light [src] before it can be used to light anything!</span>")
return TRUE
if(target == user)
user.visible_message(
"<span class='notice'>After some fiddling, [user] manages to light [user.p_their()] [cig] with [src].</span>",
"<span class='notice'>After some fiddling, you manage to light [cig] with [src].</span>,"
)
else
user.visible_message(
"<span class='notice'>After some fiddling, [user] manages to light [cig] for [target] with [src].</span>",
"<span class='notice'>After some fiddling, you manage to light [cig] for [target] with [src].</span>"
)
cig.light(user, target)
return TRUE
/obj/item/lighter/process()
var/turf/location = get_turf(src)
if(location)
location.hotspot_expose(700, 1)
return
/obj/item/lighter/update_icon_state()
icon_state = "[base_icon_state ? "[base_icon_state]" : initial(icon_state)][lighter_color ? "-[lighter_color]" : ""][lit ? "-on" : ""]"
/obj/item/lighter/update_overlays()
item_state = "[base_icon_state ? "[base_icon_state]" : initial(item_state)][lighter_color ? "-[lighter_color]" : ""][lit ? "-on" : ""]"
/obj/item/lighter/get_heat()
return lit * 1500
// ZIPPO LIGHTERS
/obj/item/lighter/zippo
name = "zippo lighter"
desc = "A premium cigarette lighter, for cool and distinguished individuals."
icon_state = "zippo"
item_state = "zippo"
is_a_zippo = TRUE
throwforce = 4
/obj/item/lighter/zippo/turn_on_lighter(mob/living/user)
. = ..()
if(world.time > next_on_message)
user.visible_message(
"<span class='rose'>Without even breaking stride, [user] flips open and lights [src] in one smooth movement.</span>",
"<span class='rose'>Without breaking your stride, you flip open and light [src] in one smooth movement.</span>",
"<span class='rose'>You hear a zippo being lit.</span>"
)
playsound(src.loc, 'sound/items/zippolight.ogg', 25, TRUE)
next_on_message = world.time + 5 SECONDS
else
to_chat(user, "<span class='notice'>You light [src].</span>")
/obj/item/lighter/zippo/turn_off_lighter(mob/living/user)
. = ..()
if(!user)
return
if(world.time > next_off_message)
user.visible_message(
"<span class='rose'>You hear a quiet click as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.</span>",
"<span class='rose'>You shut off [src] without even looking at what you're doing.</span>",
"<span class='rose'>You hear a quiet click as a zippo lighter is shut off. Wow.</span>"
)
playsound(loc, 'sound/items/zippoclose.ogg', 25, TRUE)
next_off_message = world.time + 5 SECONDS
else
to_chat(user, "<span class='notice'>You shut off [src].</span>")
/obj/item/lighter/zippo/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
var/obj/item/clothing/mask/cigarette/cig = ..()
if(!cig)
return !isnull(cig)
if(!lit)
to_chat(user, "<span class='warning'>You need to light [src] before it can be used to light anything!</span>")
return TRUE
if(target == user)
user.visible_message(
"<span class='rose'>With a single flick of [user.p_their()] wrist, [user] smoothly lights [user.p_their()] [cig.name] with [src]. Damn [user.p_theyre()] cool.</span>",
"<span class='rose'>With a single flick of your wrist, you smoothly light [cig] with [src].</span>"
)
else
user.visible_message(
"<span class='rose'>[user] whips [src] out and holds it for [target]. [user.p_their(TRUE)] arm is as steady as the unflickering flame [user.p_they()] light [cig] with. Damn [user.p_theyre()] cool.</span>",
"<span class='rose'>You whip [src] out and hold it for [target]. Your arm is as steady as the unflickering flame you light [cig] with.</span>"
)
cig.light(user, target)
return TRUE
/obj/item/lighter/zippo/show_off_message(mob/living/user)
return
/obj/item/lighter/zippo/attempt_light(mob/living/user)
return
/obj/item/lighter/zippo/nt_rep
name = "gold engraved zippo"
desc = "An engraved golden Zippo lighter with the letters \"NT\" engraved on the sides."
icon_state = "zippo-nt"
item_state = "zippo-gold"
/obj/item/lighter/zippo/blue
name = "blue zippo lighter"
desc = "A zippo lighter made of some blue metal."
icon_state = "zippo-blue"
item_state = "zippo-blue"
/obj/item/lighter/zippo/black
name = "black zippo lighter"
desc = "A black zippo lighter."
icon_state = "zippo-black"
item_state = "zippo-black"
/obj/item/lighter/zippo/engraved
name = "engraved zippo lighter"
desc = "A intricately engraved zippo lighter."
icon_state = "zippo-engraved"
/obj/item/lighter/zippo/gonzofist
name = "Gonzo Fist zippo"
desc = "A Zippo lighter with the iconic Gonzo Fist on a matte black finish."
icon_state = "zippo-gonzo"
item_state = "zippo-red"
// MARK: MATCHES
/obj/item/match
name = "match"
desc = "A simple match stick, used for lighting fine smokables."
icon = 'icons/obj/cigarettes.dmi'
icon_state = "match_unlit"
var/lit = FALSE
var/burnt = FALSE
var/smoketime = 5
w_class = WEIGHT_CLASS_TINY
origin_tech = "materials=1"
attack_verb = null
var/is_unathi_fire = FALSE
/obj/item/match/process()
var/turf/location = get_turf(src)
smoketime--
if(smoketime < 1)
matchburnout()
if(location)
location.hotspot_expose(700, 1)
return
/obj/item/match/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay = TRUE)
..()
matchignite()
/obj/item/match/extinguish_light(force)
if(!force)
return
matchburnout()
/obj/item/match/proc/matchignite()
if(!lit && !burnt)
lit = TRUE
icon_state = "match_lit"
damtype = "fire"
force = 3
hitsound = 'sound/items/welder.ogg'
item_state = "cig_on"
name = "lit match"
desc = "A match. This one is lit."
attack_verb = list("burnt","singed")
START_PROCESSING(SSobj, src)
update_icon()
return TRUE
/obj/item/match/proc/matchburnout()
if(lit)
lit = FALSE
burnt = TRUE
damtype = "brute"
force = initial(force)
icon_state = "match_burnt"
item_state = "cig_off"
name = "burnt match"
desc = "A match. This one has seen better days."
attack_verb = list("flicked")
STOP_PROCESSING(SSobj, src)
return TRUE
/obj/item/match/dropped(mob/user)
matchburnout()
. = ..()
/obj/item/match/can_enter_storage(obj/item/storage/S, mob/user)
if(lit)
to_chat(user, "<span class='warning'>[S] can't hold [initial(name)] while it's lit!</span>") // initial(name) so it doesn't say "lit" twice in a row
return FALSE
else
return TRUE
/obj/item/match/attack__legacy__attackchain(mob/living/target, mob/living/user)
if(cigarette_lighter_act(user, target))
return
if(lit && target.IgniteMob())
message_admins("[key_name_admin(user)] set [key_name_admin(target)] on fire")
log_game("[key_name(user)] set [key_name(target)] on fire")
return ..()
/obj/item/match/cigarette_lighter_act(mob/living/user, mob/living/target, obj/item/direct_attackby_item)
var/obj/item/clothing/mask/cigarette/cig = ..()
// Otherwise the later parts of this proc can be passed to the unathi's blaze and cause a runtime.
if(is_unathi_fire)
return cig
if(!cig)
return !isnull(cig)
if(!lit)
to_chat(user, "<span class='warning'>You need to light [src] before it can be used to light anything!</span>")
return TRUE
if(target == user)
user.visible_message(
"<span class='notice'>[user] lights [user.p_their()] [cig] with [src].</span>",
"<span class='notice'>You light [cig] with [src].</span>"
)
else
user.visible_message(
"<span class='notice'>[user] holds [src] out for [target], and lights [cig].</span>",
"<span class='notice'>You hold [src] out for [target], and light [user.p_their()] [cig].</span>"
)
cig.light(user, target)
matchburnout()
return TRUE
/obj/item/match/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(isdrone(user) && burnt)
C.stored_comms["wood"] += 1
qdel(src)
return TRUE
return ..()
/obj/item/match/get_heat()
return lit * 1000
/obj/item/match/firebrand
name = "firebrand"
desc = "An unlit firebrand. It makes you wonder why it's not just called a stick."
smoketime = 20 //40 seconds
/obj/item/match/firebrand/New()
..()
matchignite()
/obj/item/match/unathi
name = "small blaze"
desc = "A little flame of your own, currently located dangerously in your mouth."
icon_state = "match_unathi"
attack_verb = null
flags = DROPDEL | ABSTRACT
origin_tech = null
lit = TRUE
w_class = WEIGHT_CLASS_BULKY //to prevent it going to pockets
is_unathi_fire = TRUE
/obj/item/match/unathi/cigarette_lighter_act(mob/living/target, mob/living/user, obj/item/direct_attackby_item)
var/obj/item/clothing/mask/cigarette/cig = ..()
if(!cig)
return !isnull(cig)
if(!lit)
to_chat(user, "<span class='userdanger'>If you can see this message, please make an issue report to GitHub, something bad has happened.</span>")
return TRUE
if(target == user)
user.visible_message(
"<span class='rose'>[user] spits fire at [user.p_their()] [cig.name], igniting it.</span>",
"<span class='rose'>You spit fire at [cig], igniting it.</span>",
"<span class='warning'>You hear a brief burst of flame!</span>"
)
else
if(prob(50))
user.visible_message(
"<span class='rose'>[user] spits fire at [target], lighting [cig] in [target.p_their()] mouth and nearly burning [target.p_their()] face!</span>",
"<span class='rose'>You spit fire at [target], lighting [cig] in [target.p_their()] mouth and nearly burning [target.p_their()] face!</span>",
"<span class='warning'>You hear a brief burst of flame!</span>"
)
else
user.visible_message(
"<span class='rose'>[user] spits fire at [target], burning [target.p_their()] face and lighting [cig] in the process!</span>",
"<span class='rose'>You spit fire at [target], burning [target.p_their()] face and lighting [cig] in the process!</span>",
"<span class='warning'>You hear a brief burst of flame!</span>"
)
var/obj/item/organ/external/head/affecting = target.get_organ("head")
affecting.receive_damage(0, 5)
target.UpdateDamageIcon()
cig.light(user, target)
playsound(user.loc, 'sound/effects/unathiignite.ogg', 40, FALSE)
matchburnout()
return TRUE
/obj/item/match/unathi/Initialize(mapload)
. = ..()
START_PROCESSING(SSobj, src)
/obj/item/match/unathi/matchburnout()
if(!lit)
return
lit = FALSE //to avoid a qdel loop
qdel(src)
/obj/item/match/unathi/Destroy()
. = ..()
STOP_PROCESSING(SSobj, src)
@@ -1,67 +0,0 @@
//NEVER USE THIS IT SUX -PETETHEGOAT
/obj/item/reagent_containers/glass/paint
desc = "It's a paint bucket."
name = "paint bucket"
icon = 'icons/obj/paint.dmi'
icon_state = "paint_neutral"
item_state = "paintcan"
materials = list(MAT_METAL = 400)
w_class = WEIGHT_CLASS_NORMAL
resistance_flags = FLAMMABLE
max_integrity = 100
amount_per_transfer_from_this = 5
possible_transfer_amounts = list(5,10,20,30,50,70)
volume = 70
blocks_emissive = EMISSIVE_BLOCK_GENERIC
/obj/item/reagent_containers/glass/paint/interact_with_atom(atom/target, mob/living/user, list/modifiers)
if(!is_open_container())
return ITEM_INTERACT_COMPLETE
if(istype(target) && reagents.total_volume >= 5)
user.visible_message("<span class='warning'>[target] has been splashed with something by [user]!</span>")
spawn(5)
reagents.reaction(target, REAGENT_TOUCH)
reagents.remove_any(5)
return ITEM_INTERACT_COMPLETE
else
return ..()
/obj/item/reagent_containers/glass/paint/red
name = "red paint bucket"
icon_state = "paint_red"
list_reagents = list("paint_red" = 70)
/obj/item/reagent_containers/glass/paint/green
name = "green paint bucket"
icon_state = "paint_green"
list_reagents = list("paint_green" = 70)
/obj/item/reagent_containers/glass/paint/blue
name = "blue paint bucket"
icon_state = "paint_blue"
list_reagents = list("paint_blue" = 70)
/obj/item/reagent_containers/glass/paint/yellow
name = "yellow paint bucket"
icon_state = "paint_yellow"
list_reagents = list("paint_yellow" = 70)
/obj/item/reagent_containers/glass/paint/violet
name = "violet paint bucket"
icon_state = "paint_violet"
list_reagents = list("paint_violet" = 70)
/obj/item/reagent_containers/glass/paint/black
name = "black paint bucket"
icon_state = "paint_black"
list_reagents = list("paint_black" = 70)
/obj/item/reagent_containers/glass/paint/white
name = "white paint bucket"
icon_state = "paint_white"
list_reagents = list("paint_white" = 70)
/obj/item/reagent_containers/glass/paint/remover
name = "paint remover bucket"
list_reagents = list("paint_remover" = 70)
@@ -1,11 +0,0 @@
/obj/item/pai_cable/proc/plugin(obj/machinery/M as obj, mob/user as mob)
if(isairlock(M) || istype(M, /obj/machinery/camera))
user.visible_message("[user] inserts [src] into a data port on [M].", "You insert [src] into a data port on [M].", "You hear the satisfying click of a wire jack fastening into place.")
user.drop_item()
src.loc = M
src.machine = M
else
user.visible_message("[user] dumbly fumbles to find a place on [M] to plug in [src].", "There aren't any ports on [M] that match the jack belonging to [src].")
/obj/item/pai_cable/attack__legacy__attackchain(obj/machinery/M as obj, mob/user as mob)
src.plugin(M, user)
@@ -1,120 +0,0 @@
/obj/item/picket_sign
name = "blank picket sign"
desc = "It's blank."
icon_state = "picket"
item_state = "picket"
force = 5
w_class = WEIGHT_CLASS_BULKY
attack_verb = list("bashed","smacked")
resistance_flags = FLAMMABLE
new_attack_chain = TRUE
/// The cooldown tracking when we can next wave the sign
COOLDOWN_DECLARE(wave_cooldown)
/// What does the sign say?
var/label = ""
/obj/item/picket_sign/attack_by(obj/item/attacking, mob/user, params)
if(is_pen(attacking) || istype(attacking, /obj/item/toy/crayon))
var/txt = tgui_input_text(user, "What would you like to write on the sign?", "Sign Label", max_length = 30)
if(isnull(txt))
return
label = txt
src.name = "[label] sign"
desc = "It reads: [label]"
..()
/obj/item/picket_sign/activate_self(mob/user)
. = ..()
if(!COOLDOWN_FINISHED(src, wave_cooldown))
user.show_message("<span class='warning'>Your arm is too tired to do that again so soon!</span>")
return
if(label)
user.visible_message("<span class='notice'>[user] waves around \the \"[label]\" sign.</span>")
else
user.visible_message("<span class='notice'>[user] waves around blank sign.</span>")
user.changeNext_move(CLICK_CD_MELEE)
COOLDOWN_START(src, wave_cooldown, 8 SECONDS)
/obj/item/picket_sign/after_attack(atom/target, mob/user, proximity_flag, click_parameters)
. = ..()
if(user.a_intent != INTENT_HELP)
return
if(!isturf(target))
return
var/turf/target_turf = target
if(target_turf == get_turf(user))
to_chat(user, "<span class='notice'>You cannot place [src] under yourself.</span>")
return
if(locate(/obj/structure/custom_sign) in target_turf) // No putting signs on signs
to_chat(user, "<span class='notice'>There's already a sign there!</span>")
return
user.visible_message("<span class='notice'>[user] starts to attach [src] to [target].</span>", "<span class='notice'>You start to attach [src] to [target].</span>")
if(do_after(user, 2 SECONDS, target = target_turf))
if(iswallturf(target))
new /obj/structure/custom_sign/wall_sign(user.loc, label, get_dir(user, target_turf))
else
new /obj/structure/custom_sign(target_turf, label)
qdel(src)
/obj/structure/custom_sign
name = "floor sign"
anchored = TRUE
max_integrity = 50
icon_state = "floor_sign"
/// What does the sign say?
var/label = ""
new_attack_chain = TRUE
/obj/structure/custom_sign/New(turf/loc, new_label)
. = ..()
if(new_label)
change_label(new_label)
/obj/structure/custom_sign/item_interaction(mob/living/user, obj/item/used, list/modifiers)
if(is_pen(used) || istype(used, /obj/item/toy/crayon))
var/txt = tgui_input_text(user, "What would you like to write on the sign?", "Sign Label", max_length = 30)
if(isnull(txt))
return ITEM_INTERACT_COMPLETE
change_label(txt)
add_fingerprint(user)
return ITEM_INTERACT_COMPLETE
..()
/obj/structure/custom_sign/proc/change_label(new_label)
label = new_label
name = "[new_label] sign"
desc = "It reads: [new_label]"
/obj/structure/custom_sign/wrench_act(mob/living/user, obj/item/I)
. = TRUE
user.visible_message("<span class='notice'>[user] starts to detach [src].</span>", "<span class='notice'>You start to detach [src].</span>")
if(!I.use_tool(src, user, 2 SECONDS, volume = I.tool_volume))
return
var/obj/item/picket_sign/picket = new /obj/item/picket_sign(loc)
if(label)
picket.label = label
picket.name = "[label] sign"
picket.desc = "It reads: [label]"
qdel(src)
/obj/structure/custom_sign/wall_sign
name = "wall sign"
icon_state = "wall_sign"
/obj/structure/custom_sign/wall_sign/New(turf/loc, new_label, direction)
. = ..()
// Offset 24 pixels in direction of dir. This allows the sign to be embedded in a wall
setDir(direction)
set_pixel_offsets_from_dir(24, -24, 24, -24)
update_icon()
/datum/crafting_recipe/picket_sign
name = "Picket Sign"
result = list(/obj/item/picket_sign)
reqs = list(/obj/item/stack/rods = 1,
/obj/item/stack/sheet/cardboard = 2)
time = 80
category = CAT_MISC
-373
View File
@@ -1,373 +0,0 @@
/*Contains:
Rapid Pipe Dispenser
*/
#define RPD_COOLDOWN_TIME 4 //How long should we have to wait between dispensing pipes?
#define RPD_WALLBUILD_TIME 40 //How long should drilling into a wall take?
#define RPD_MENU_ROTATE "Rotate pipes" //Stuff for radial menu
#define RPD_MENU_FLIP "Flip pipes" //Stuff for radial menu
#define RPD_MENU_DELETE "Delete pipes" //Stuff for radial menu
/obj/item/rpd
name = "rapid pipe dispenser"
desc = "This device can rapidly dispense atmospherics and disposals piping, manipulate loose piping, and recycle any detached pipes it is applied to."
icon = 'icons/obj/tools.dmi'
icon_state = "rpd"
flags = CONDUCT
force = 10
throwforce = 10
throw_speed = 3
throw_range = 5
materials = list(MAT_METAL = 75000, MAT_GLASS = 37500)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 50)
resistance_flags = FIRE_PROOF
origin_tech = "engineering=4;materials=2"
var/datum/effect_system/spark_spread/spark_system
var/lastused
var/iconrotation = 0 //Used to orient icons and pipes
var/mode = RPD_ATMOS_MODE //Disposals, atmospherics, etc.
var/pipe_category = RPD_ATMOS_PIPING //For TGUI menus, this is a subtype of pipes e.g. scrubbers pipes, devices
var/whatpipe = PIPE_SIMPLE_STRAIGHT //What kind of atmos pipe is it?
var/whatdpipe = PIPE_DISPOSALS_STRAIGHT //What kind of disposals pipe is it?
var/whatttube = PIPE_TRANSIT_TUBE
var/spawndelay = RPD_COOLDOWN_TIME
var/walldelay = RPD_WALLBUILD_TIME
var/ranged = FALSE
var/primary_sound = 'sound/machines/click.ogg'
var/alt_sound = null
var/auto_wrench_toggle = TRUE
var/pipe_label = null
//Lists of things
var/list/mainmenu = list(
list("category" = "Atmospherics", "mode" = RPD_ATMOS_MODE, "icon" = "wrench"),
list("category" = "Disposals", "mode" = RPD_DISPOSALS_MODE, "icon" = "recycle"),
list("category" = "Transit", "mode" = RPD_TRANSIT_MODE, "icon" = "subway"),
list("category" = "Rotate", "mode" = RPD_ROTATE_MODE, "icon" = "sync-alt"),
list("category" = "Flip", "mode" = RPD_FLIP_MODE, "icon" = "arrows-alt-h"),
list("category" = "Recycle", "mode" = RPD_DELETE_MODE, "icon" = "trash"))
var/list/pipemenu = list(
list("category" = "Normal", "pipemode" = RPD_ATMOS_PIPING),
list("category" = "Supply", "pipemode" = RPD_SUPPLY_PIPING),
list("category" = "Scrubber", "pipemode" = RPD_SCRUBBERS_PIPING),
list("category" = "Devices", "pipemode" = RPD_DEVICES),
list("category" = "Heat exchange", "pipemode" = RPD_HEAT_PIPING))
/obj/item/rpd/Initialize(mapload)
. = ..()
spark_system = new /datum/effect_system/spark_spread()
spark_system.set_up(1, 0, src)
spark_system.attach(src)
/obj/item/rpd/Destroy()
QDEL_NULL(spark_system)
return ..()
/obj/item/rpd/bluespace
name = "bluespace rapid pipe dispenser"
desc = "This device can rapidly dispense atmospherics and disposals piping, manipulate loose piping, and recycle any detached pipes it is applied to, at any range."
icon_state = "brpd"
materials = list(MAT_METAL = 75000, MAT_GLASS = 37500, MAT_SILVER = 3000)
origin_tech = "engineering=4;materials=2;bluespace=3"
ranged = TRUE
primary_sound = 'sound/items/PSHOOM.ogg'
alt_sound = 'sound/items/PSHOOM_2.ogg'
//Procs
/obj/item/rpd/proc/activate_rpd(delay) //Maybe makes sparks and activates cooldown if there is a delay
if(alt_sound && prob(3))
playsound(src, alt_sound, 50, 1)
else
playsound(src, primary_sound, 50, 1)
if(prob(15) && !ranged)
spark_system.start()
if(delay)
lastused = world.time
/obj/item/rpd/proc/can_dispense_pipe(pipe_id, pipe_type) //Returns TRUE if this is a legit pipe we can dispense, otherwise returns FALSE
for(var/list/L in GLOB.rpd_pipe_list)
if(pipe_type != L["pipe_type"]) //Sometimes pipes in different categories have the same pipe_id, so we need to skip anything not in the category we want
continue
if(pipe_id == L["pipe_id"]) //Found the pipe, we can dispense it
return TRUE
/obj/item/rpd/proc/create_atmos_pipe(mob/user, turf/T) //Make an atmos pipe, meter, or gas sensor
if(!can_dispense_pipe(whatpipe, RPD_ATMOS_MODE))
CRASH("Failed to spawn [get_pipe_name(whatpipe, PIPETYPE_ATMOS)] - possible tampering detected") //Damn dirty apes -- I mean hackers
var/obj/item/pipe/P
if(whatpipe == PIPE_GAS_SENSOR)
P = new /obj/item/pipe_gsensor(T)
else if(whatpipe == PIPE_METER)
P = new /obj/item/pipe_meter(T)
else
P = new(T, whatpipe, iconrotation) //Make the pipe, BUT WAIT! There's more!
if(!iconrotation && P.is_bent_pipe()) //Automatically rotates dispensed pipes if the user selected auto-rotation
P.dir = turn(user.dir, 135)
else if(!iconrotation && (P.pipe_type in list(PIPE_CONNECTOR, PIPE_UVENT, PIPE_SCRUBBER, PIPE_HEAT_EXCHANGE, PIPE_CAP, PIPE_SUPPLY_CAP, PIPE_SCRUBBERS_CAP, PIPE_INJECTOR, PIPE_PASV_VENT))) //Some pipes dispense oppositely to what you'd expect, but we don't want to do anything if they selected a direction
P.dir = turn(user.dir, -180)
else if(iconrotation && P.is_bent_pipe()) //If user selected a rotation and the pipe is bent
P.dir = turn(iconrotation, -45)
else if(!iconrotation) //If user selected a rotation
P.dir = user.dir
to_chat(user, "<span class='notice'>[src] rapidly dispenses [P]!</span>")
P.label = pipe_label
automatic_wrench_down(user, P)
activate_rpd(TRUE)
/obj/item/rpd/proc/create_disposals_pipe(mob/user, turf/T) //Make a disposals pipe / construct
if(!can_dispense_pipe(whatdpipe, RPD_DISPOSALS_MODE))
CRASH("Failed to spawn [get_pipe_name(whatdpipe, PIPETYPE_DISPOSAL)] - possible tampering detected")
var/obj/structure/disposalconstruct/P = new(T, whatdpipe, iconrotation)
if(!iconrotation) //Automatic rotation
P.dir = user.dir
if(!iconrotation && whatdpipe != PIPE_DISPOSALS_JUNCTION_RIGHT) //Disposals pipes are in the opposite direction to atmos pipes, so we need to flip them. Junctions don't have this quirk though
P.flip()
to_chat(user, "<span class='notice'>[src] rapidly dispenses [P]!</span>")
automatic_wrench_down(user, P)
activate_rpd(TRUE)
/obj/item/rpd/proc/create_transit_tube(mob/user, turf/dest)
if(!can_dispense_pipe(whatttube, PIPETYPE_TRANSIT))
CRASH("Failed to spawn [get_pipe_name(whatttube, PIPETYPE_TRANSIT)] - possible tampering detected")
for(var/datum/pipes/transit/T in GLOB.construction_pipe_list)
if(T.pipe_id == whatttube)
var/obj/structure/transit_tube_construction/S = new T.construction_type(dest)
if(!istype(S))
CRASH("found [S] when constructing transit tube but expected /obj/structure/transit_tube_construction")
S.dir = iconrotation ? iconrotation : user.dir
to_chat(user, "<span class='notice'>[src] rapidly dispenses [S]!</span>")
automatic_wrench_down(user, S)
activate_rpd(TRUE)
/obj/item/rpd/proc/rotate_all_pipes(mob/user, turf/T) //Rotate all pipes on a turf
for(var/obj/item/pipe/P in T)
P.rotate()
for(var/obj/structure/disposalconstruct/D in T)
D.rotate()
for(var/obj/structure/transit_tube_construction/tube in T)
tube.rotate()
/obj/item/rpd/proc/flip_all_pipes(mob/user, turf/T) //Flip all pipes on a turf
for(var/obj/item/pipe/P in T)
P.flip()
for(var/obj/structure/disposalconstruct/D in T)
D.flip()
for(var/obj/structure/transit_tube_construction/tube in T)
tube.flip()
/obj/item/rpd/proc/delete_all_pipes(mob/user, turf/T) //Delete all pipes on a turf
var/eaten
for(var/obj/item/pipe/P in T)
if(P.pipe_type == PIPE_CIRCULATOR) //Skip TEG heat circulators, they aren't really pipes
continue
QDEL_NULL(P)
eaten = TRUE
for(var/obj/item/pipe_gsensor/G in T)
QDEL_NULL(G)
eaten = TRUE
for(var/obj/item/pipe_meter/M in T)
QDEL_NULL(M)
eaten = TRUE
for(var/obj/structure/disposalconstruct/D in T)
if(!D.anchored)
QDEL_NULL(D)
eaten = TRUE
for(var/obj/structure/transit_tube_construction/C in T)
QDEL_NULL(C)
eaten = TRUE
if(eaten)
to_chat(user, "<span class='notice'>[src] sucks up the loose pipes on [T].")
activate_rpd()
else
to_chat(user, "<span class='notice'>There were no loose pipes on [T].</span>")
/obj/item/rpd/proc/delete_single_pipe(mob/user, obj/P) //Delete a single pipe
to_chat(user, "<span class='notice'>[src] sucks up [P].</span>")
QDEL_NULL(P)
activate_rpd()
/**
* Automatically wrenches down an atmos device/pipe if the auto_wrench_toggle is TRUE.
* Arguments:
* * user - the user of the RPD.
* * target - the pipe/device/tube being placed by the RPD.
*/
/obj/item/rpd/proc/automatic_wrench_down(mob/living/user, obj/item/target)
if(!auto_wrench_toggle)
return
if(mode == RPD_TRANSIT_MODE)
if(target.screwdriver_act(user, src) & RPD_TOOL_SUCCESS)
playsound(src, 'sound/items/impactwrench.ogg', 50, TRUE)
return
if(target.wrench_act(user, src) & RPD_TOOL_SUCCESS)
playsound(src, 'sound/items/impactwrench.ogg', 50, TRUE)
return
// TGUI stuff
/obj/item/rpd/attack_self__legacy__attackchain(mob/user)
ui_interact(user)
/obj/item/rpd/ui_state(mob/user)
return GLOB.inventory_state
/obj/item/rpd/ui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RPD", name)
ui.open()
/obj/item/rpd/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/rpd)
)
/obj/item/rpd/AltClick(mob/user)
radial_menu(user)
/obj/item/rpd/ui_data(mob/user)
var/list/data = list()
data["iconrotation"] = iconrotation
data["mainmenu"] = mainmenu
data["mode"] = mode
data["pipelist"] = GLOB.rpd_pipe_list
data["pipemenu"] = pipemenu
data["pipe_category"] = pipe_category
data["whatdpipe"] = whatdpipe
data["whatpipe"] = whatpipe
data["whatttube"] = whatttube
data["auto_wrench_toggle"] = auto_wrench_toggle
return data
/obj/item/rpd/ui_act(action, list/params)
if(..())
return
. = TRUE
switch(action)
if("iconrotation")
iconrotation = isnum(params[action]) ? params[action] : text2num(params[action])
if("whatpipe")
whatpipe = isnum(params[action]) ? params[action] : text2num(params[action])
if("whatdpipe")
whatdpipe = isnum(params[action]) ? params[action] : text2num(params[action])
if("whatttube")
whatttube = isnum(params[action]) ? params[action] : text2num(params[action])
if("pipe_category")
pipe_category = isnum(params[action]) ? params[action] : text2num(params[action])
if("mode")
mode = isnum(params[action]) ? params[action] : text2num(params[action])
if("auto_wrench_toggle")
auto_wrench_toggle = !auto_wrench_toggle
if("set_label")
pipe_label = params[action]
//RPD radial menu
/obj/item/rpd/proc/check_menu(mob/living/user)
if(!istype(user))
return
if(user.incapacitated())
return
if(loc != user)
return
return TRUE
/obj/item/rpd/proc/radial_menu(mob/user)
if(!check_menu(user))
to_chat(user, "<span class='notice'>You can't do that right now!</span>")
return
var/list/choices = list(
RPD_MENU_ROTATE = image(icon = 'icons/obj/interface.dmi', icon_state = "rpd_rotate"),
RPD_MENU_FLIP = image(icon = 'icons/obj/interface.dmi', icon_state = "rpd_flip"),
RPD_MENU_DELETE = image(icon = 'icons/obj/interface.dmi', icon_state = "rpd_delete"),
"UI" = image(icon = 'icons/obj/interface.dmi', icon_state = "ui_interact")
)
var/selected_mode = show_radial_menu(user, src, choices, custom_check = CALLBACK(src, PROC_REF(check_menu), user))
if(!check_menu(user))
return
if(selected_mode == "UI")
ui_interact(user)
else
switch(selected_mode)
if(RPD_MENU_ROTATE)
mode = RPD_ROTATE_MODE
if(RPD_MENU_FLIP)
mode = RPD_FLIP_MODE
if(RPD_MENU_DELETE)
mode = RPD_DELETE_MODE
else
return //Either nothing was selected, or an invalid mode was selected
to_chat(user, "<span class='notice'>You set [src]'s mode.</span>")
/obj/item/rpd/afterattack__legacy__attackchain(atom/target, mob/user, proximity)
..()
if(isstorage(target))
var/obj/item/storage/S = target
if(!S.can_be_inserted(src, stop_messages = TRUE))
return
if(loc != user)
return
if(!proximity && !ranged)
return
if(world.time < lastused + spawndelay)
return
var/turf/T = get_turf(target)
if(!T)
return
if(target != T)
// We only check the rpd_act of the target if it isn't the turf, because otherwise
// (A) blocked turfs can be acted on, and (B) unblocked turfs get acted on twice.
if(target.rpd_act(user, src))
// If the object we are clicking on has a valid RPD interaction for just that specific object, do that and nothing else.
// Example: clicking on a pipe with a RPD in rotate mode should rotate that pipe and ignore everything else on the tile.
if(ranged)
user.Beam(T, icon_state="rped_upgrade", icon='icons/effects/effects.dmi', time=5)
return
// If we get this far, we have to check every object in the tile, to make sure that none of them block RPD usage on this tile.
// This is done by calling rpd_blocksusage on every /obj in the tile. If any block usage, fail at this point.
for(var/obj/O in T)
if(O.rpd_blocksusage())
to_chat(user, "<span class='warning'>[O] blocks [src]!</span>")
return
// If we get here, then we're effectively acting on the turf, probably placing a pipe.
if(ranged) //woosh beam if bluespaced at a distance
if(get_dist(src, T) >= (user.client.maxview() / 2))
message_admins("\[EXPLOIT] [key_name_admin(user)] attempted to place pipes with a BRPD via a camera console. (Attempted range exploit)")
playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
to_chat(user, "<span class='notice'>ERROR: \The [T] is out of [src]'s range!</span>")
return
if(!(user in hearers(12, T))) // Checks if user can hear the target turf, cause viewers doesnt work for it.
to_chat(user, "<span class='warning'>[src] needs full visibility to determine the dispensing location.</span>")
playsound(src, 'sound/machines/synth_no.ogg', 50, TRUE)
return
user.Beam(T, icon_state = "rped_upgrade", icon = 'icons/effects/effects.dmi', time = 0.5 SECONDS)
T.rpd_act(user, src)
/obj/item/rpd/attack_obj__legacy__attackchain(obj/O, mob/living/user)
if(user.a_intent != INTENT_HARM)
if(istype(O, /obj/machinery/atmospherics/pipe))
return
else if(istype(O, /obj/structure/disposalconstruct))
return
else if(istype(O, /obj/structure/transit_tube_construction))
return
return ..()
#undef RPD_COOLDOWN_TIME
#undef RPD_WALLBUILD_TIME
#undef RPD_MENU_ROTATE
#undef RPD_MENU_FLIP
#undef RPD_MENU_DELETE
@@ -1,75 +0,0 @@
/obj/item/teleportation_scroll
name = "scroll of teleportation"
desc = "A scroll for moving around."
icon = 'icons/obj/wizard.dmi'
icon_state = "scroll"
var/uses = 4
w_class = WEIGHT_CLASS_SMALL
item_state = "paper"
throw_speed = 4
throw_range = 20
origin_tech = "bluespace=6"
resistance_flags = FLAMMABLE
/obj/item/teleportation_scroll/apprentice
name = "lesser scroll of teleportation"
uses = 1
origin_tech = "bluespace=5"
/obj/item/teleportation_scroll/examine(mob/user)
. = ..()
. += "<span class='notice'>Number of uses: [uses]. This scroll will vanish after the final use.</span>"
. += "<span class='notice'>P.S. Don't forget to bring your gear, you'll need it to cast most spells.</span>"
/obj/item/teleportation_scroll/attack_self__legacy__attackchain(mob/living/user)
if(!uses) //somehow?
to_chat(user, "<span class='warning'>You attempt to read the scroll but it disintegrates in your hand, it appears that is has run out of charges!</span>")
qdel(src)
return
var/picked_area
picked_area = tgui_input_list(user, "Area to jump to", "Teleport where?", SSmapping.teleportlocs)
if(!picked_area)
return
var/area/thearea = SSmapping.teleportlocs[picked_area]
if(user.stat || user.restrained())
return
if(!(user == loc || (in_range(src, user) && isturf(user.loc))))
return //They can't use it if they put it in their bag or drop it and walk off, but if they are stood next to it they can.
if(thearea.tele_proof && !istype(thearea, /area/wizard_station)) //Nowhere in SSmapping.teleportlocs should be tele_proof, but better safe than sorry
to_chat(user, "<span class='warning'>A mysterious force disrupts your arcane spell matrix, and you remain where you are.</span>")
return
var/datum/effect_system/smoke_spread/smoke = new
smoke.set_up(5, FALSE, get_turf(user))
smoke.attach(user)
smoke.start()
var/list/L = list()
for(var/turf/T in get_area_turfs(thearea.type))
if(T.is_blocked_turf())
continue
L.Add(T)
if(!length(L))
to_chat(user, "<span class='warning'>The spell matrix was unable to locate a suitable teleport destination for an unknown reason. Sorry.</span>")
return
if(user && user.buckled)
user.unbuckle(force = TRUE)
if(user?.has_buckled_mobs())
user.unbuckle_all_mobs(force = TRUE)
user.forceMove(pick(L))
smoke.start()
uses--
if(!uses)
to_chat(user, "<span class='warning'>The scroll fizzles out of existence as the last of the magic within fades.</span>")
qdel(src)
user.update_action_buttons_icon() //Update action buttons as some spells might now be castable
-125
View File
@@ -1,125 +0,0 @@
/obj/item/soap
name = "soap"
desc = "A cheap bar of soap. Doesn't smell."
gender = PLURAL
icon = 'icons/obj/janitor.dmi'
icon_state = "soap"
lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
w_class = WEIGHT_CLASS_TINY
throw_speed = 4
throw_range = 20
discrete = 1
var/cleanspeed = 50 //slower than mop
var/times_eaten = 0 //How many times a Drask has chewed on this bar of soap
var/max_bites = 30 //The maximum amount of bites before the soap is depleted
/obj/item/soap/Initialize(mapload)
. = ..()
AddComponent(/datum/component/slippery, src, 8 SECONDS, 100, 0, FALSE)
/obj/item/soap/afterattack__legacy__attackchain(atom/target, mob/user, proximity)
if(!proximity)
return
if(user.zone_selected == "mouth" && ishuman(target)) // cleaning out someone's mouth is a different act
return
if(target == user && user.a_intent == INTENT_GRAB && ishuman(target))
var/mob/living/carbon/human/muncher = user
if(muncher && isdrask(muncher))
eat_soap(muncher)
return
target.cleaning_act(user, src, cleanspeed)
/obj/item/soap/add_blood(list/blood_dna, b_color)
return
/obj/item/soap/proc/eat_soap(mob/living/carbon/human/drask/user)
times_eaten++
playsound(user.loc, 'sound/items/eatfood.ogg', 50, 0)
user.adjust_nutrition(5)
user.reagents.add_reagent("soapreagent", 3)
if(times_eaten < max_bites)
to_chat(user, "<span class='notice'>You take a bite of [src]. Delicious!</span>")
else
to_chat(user, "<span class='notice'>You finish eating [src].</span>")
qdel(src)
/obj/item/soap/examine(mob/user)
. = ..()
if(!user.Adjacent(src) || !times_eaten)
return
if(times_eaten < (max_bites * 0.3))
. += "<span class='notice'>[src] has bite marks on it!</span>"
else if(times_eaten < (max_bites * 0.6))
. += "<span class='notice'>Big chunks of [src] have been chewed off!</span>"
else if(times_eaten < (max_bites * 0.9))
. += "<span class='notice'>Most of [src] has been gnawed away!</span>"
else
. += "<span class='notice'>[src] has been eaten down to a sliver!</span>"
/obj/item/soap/attack__legacy__attackchain(mob/target as mob, mob/user as mob)
if(target && user && ishuman(target) && ishuman(user) && !target.stat && !user.stat && user.zone_selected == "mouth")
user.visible_message("<span class='warning'>[user] starts washing [target]'s mouth out with [name]!</span>")
if(do_after(user, cleanspeed, target = target))
user.visible_message("<span class='warning'>[user] washes [target]'s mouth out with [name]!</span>")
target.reagents.add_reagent("soapreagent", 6)
return
..()
/obj/item/soap/can_clean()
return TRUE
/obj/item/soap/nanotrasen
desc = "A Nanotrasen brand bar of soap. Smells of plasma."
icon_state = "soapnt"
/obj/item/soap/homemade
desc = "A homemade bar of soap. Smells of... well...."
icon_state = "soaphome"
cleanspeed = 45 // a little faster to reward chemists for going to the effort
/obj/item/soap/ducttape
desc = "A homemade bar of soap. It seems to be gibs and tape..Will this clean anything?"
icon_state = "soapgibs"
/obj/item/soap/ducttape/afterattack__legacy__attackchain(atom/target, mob/user as mob, proximity)
if(!proximity) return
if(user.client && (target in user.client.screen))
to_chat(user, "<span class='notice'>You need to take that [target.name] off before 'cleaning' it.</span>")
else
user.visible_message("<span class='warning'>[user] begins to smear [src] on \the [target.name].</span>")
if(do_after(user, cleanspeed, target = target))
to_chat(user, "<span class='notice'>You 'clean' \the [target.name].</span>")
if(issimulatedturf(target))
new /obj/effect/decal/cleanable/blood/gibs/cleangibs(target)
else if(iscarbon(target))
for(var/obj/item/carried_item in target.contents)
if(!istype(carried_item, /obj/item/bio_chip))//If it's not an implant.
carried_item.add_mob_blood(target)//Oh yes, there will be blood...
var/mob/living/carbon/human/H = target
H.make_bloody_hands(H.get_blood_dna_list(), H.get_blood_color(), 0)
H.bloody_body(target)
return
/obj/item/soap/deluxe
desc = "A luxury bar of soap. Smells of honey."
icon_state = "soapdeluxe"
cleanspeed = 40 //slightly better because deluxe -- captain gets one of these
/obj/item/soap/deluxe/laundry
name = "laundry soap"
desc = "Very cheap but effective soap. Dries out the skin."
icon_state = "soapsoviet"
/obj/item/soap/syndie
desc = "An untrustworthy bar of soap made of strong chemical agents that dissolve blood faster."
icon_state = "soapsyndie"
cleanspeed = 10 //much faster than mop so it is useful for traitors who want to clean crime scenes
/obj/item/soap/ds
desc = "A very intimidating, jet-black bar of soap with a skull embossed on the top. Whatever this thing is made of, it can clean any mess in the blink of an eye."
icon_state = "soapds"
cleanspeed = 5
-73
View File
@@ -1,73 +0,0 @@
/obj/item/staff
name = "wizards staff"
desc = "Apparently a staff used by the wizard."
icon = 'icons/obj/wizard.dmi'
icon_state = "staff"
lefthand_file = 'icons/mob/inhands/staves_lefthand.dmi'
righthand_file = 'icons/mob/inhands/staves_righthand.dmi'
force = 3.0
throwforce = 5.0
throw_speed = 1
throw_range = 5
w_class = WEIGHT_CLASS_SMALL
armour_penetration_percentage = 100
attack_verb = list("bludgeoned", "whacked", "disciplined")
resistance_flags = FLAMMABLE
/obj/item/staff/Initialize(mapload)
. = ..()
AddComponent(/datum/component/two_handed)
/obj/item/staff/broom
name = "broom"
desc = "Used for sweeping, and flying into the night while cackling. Black cat not included."
icon_state = "broom"
item_state = "broom0"
/obj/item/staff/broom/Initialize(mapload)
. = ..()
AddComponent(/datum/component/two_handed, force_wielded = 5, force_unwielded = 3, wield_callback = CALLBACK(src, PROC_REF(wield)), unwield_callback = CALLBACK(src, PROC_REF(unwield)))
/obj/item/staff/broom/proc/wield(obj/item/source, mob/user)
attack_verb = list("rammed into", "charged at")
user.update_inv_l_hand()
user.update_inv_r_hand()
if(iswizard(user))
ADD_TRAIT(user, TRAIT_FLYING, "broomstick")
user.say("QUID 'ITCH")
animate(user, pixel_y = pixel_y + 10 , time = 10, loop = 1, easing = SINE_EASING)
to_chat(user, "<span class='notice'>You hold [src] between your legs.</span>")
/obj/item/staff/broom/proc/unwield(obj/item/source, mob/user)
attack_verb = list("bludgeoned", "whacked", "cleaned")
user.update_inv_l_hand()
user.update_inv_r_hand()
if(iswizard(user))
REMOVE_TRAIT(user, TRAIT_FLYING, "broomstick")
animate(user, pixel_y = pixel_y + 10 , time = 1, loop = 1)
animate(user, pixel_y = pixel_y, time = 10, loop = 1, easing = SINE_EASING)
animate(user)
/obj/item/staff/broom/attackby__legacy__attackchain(obj/O, mob/user)
if(istype(O, /obj/item/clothing/mask/horsehead))
new/obj/item/staff/broom/horsebroom(get_turf(src))
user.unequip(O)
qdel(O)
qdel(src)
return
..()
/obj/item/staff/broom/dropped(mob/user)
REMOVE_TRAIT(user, TRAIT_FLYING, "broomstick")
..()
/obj/item/staff/broom/horsebroom
name = "broomstick horse"
desc = "Saddle up!"
icon_state = "horsebroom"
item_state = "horsebroom0"
/obj/item/staff/broom/horsebroom/attack_self__legacy__attackchain(mob/user as mob)
..()
item_state = "horsebroom[HAS_TRAIT(src, TRAIT_WIELDED) ? 1 : 0]"
@@ -1,288 +0,0 @@
////////////////////////////////////////
// MARK: RPEDs
////////////////////////////////////////
/obj/item/storage/part_replacer
name = "Rapid Part Exchange Device"
desc = "Special mechanical module made to store, sort, and apply standard machine parts."
icon_state = "RPED"
item_state = "RPED"
w_class = WEIGHT_CLASS_HUGE
can_hold = list(
/obj/item/stock_parts,
// This type is part of can_hold, but is added separately in Initialize to avoid picking up unwanted subtypes.
// /obj/item/reagent_containers/glass/beaker,
/obj/item/reagent_containers/glass/beaker/large,
/obj/item/reagent_containers/glass/beaker/bluespace
)
storage_slots = 50
use_to_pickup = TRUE
allow_quick_gather = TRUE
allow_quick_empty = TRUE
display_contents_with_number = TRUE
max_w_class = WEIGHT_CLASS_NORMAL
max_combined_w_class = 100
usesound = 'sound/items/rped.ogg'
var/works_from_distance = FALSE
var/primary_sound = 'sound/items/rped.ogg'
var/alt_sound = null
/obj/item/storage/part_replacer/Initialize(mapload)
. = ..()
can_hold[/obj/item/reagent_containers/glass/beaker] = TRUE
/obj/item/storage/part_replacer/can_be_inserted(obj/item/I, stop_messages = FALSE)
if(!istype(I, /obj/item/reagent_containers/glass/beaker))
return ..()
var/obj/item/reagent_containers/glass/beaker/B = I
if(B.reagents?.total_volume)
if(!stop_messages)
to_chat(usr, "<span class='warning'>[src] cannot hold [I] while it contains liquid.</span>")
return FALSE
return ..()
/obj/item/storage/part_replacer/afterattack__legacy__attackchain(obj/machinery/M, mob/user, proximity_flag, params)
if(!istype(M))
return ..()
if(!proximity_flag)
if(!works_from_distance)
return
if(get_dist(user, M) > (user.client.maxview() / 2))
message_admins("\[EXPLOIT] [key_name_admin(user)] attempted to upgrade machinery with a BRPED via a camera console (attempted range exploit).")
playsound(src, 'sound/machines/synth_no.ogg', 15, TRUE)
to_chat(user, "<span class='notice'>ERROR: [M] is out of [src]'s range!</span>")
return
if(M.component_parts)
M.exchange_parts(user, src)
if(works_from_distance)
user.Beam(M, icon_state="rped_upgrade", icon='icons/effects/effects.dmi', time=5)
/obj/item/storage/part_replacer/tier4/populate_contents()
for(var/amount in 1 to 30)
new /obj/item/stock_parts/capacitor/quadratic(src)
new /obj/item/stock_parts/manipulator/femto(src)
new /obj/item/stock_parts/matter_bin/bluespace(src)
new /obj/item/stock_parts/micro_laser/quadultra(src)
new /obj/item/stock_parts/scanning_module/triphasic(src)
new /obj/item/stock_parts/cell/bluespace(src)
new /obj/item/reagent_containers/glass/beaker/bluespace(src)
////////////////////////////////////////
// Bluespace Part Replacer
////////////////////////////////////////
/obj/item/storage/part_replacer/bluespace
name = "bluespace rapid part exchange device"
desc = "A version of the RPED that allows for replacement of parts and scanning from a distance, along with higher capacity for parts."
icon_state = "BS_RPED"
item_state = "BS_RPED"
w_class = WEIGHT_CLASS_NORMAL
storage_slots = 400
max_combined_w_class = 800
works_from_distance = TRUE
primary_sound = 'sound/items/pshoom.ogg'
alt_sound = 'sound/items/pshoom_2.ogg'
usesound = 'sound/items/pshoom.ogg'
toolspeed = 0.5
/obj/item/storage/part_replacer/bluespace/tier4/populate_contents()
for(var/amount in 1 to 30)
new /obj/item/stock_parts/capacitor/quadratic(src)
new /obj/item/stock_parts/manipulator/femto(src)
new /obj/item/stock_parts/matter_bin/bluespace(src)
new /obj/item/stock_parts/micro_laser/quadultra(src)
new /obj/item/stock_parts/scanning_module/triphasic(src)
new /obj/item/stock_parts/cell/bluespace(src)
new /obj/item/reagent_containers/glass/beaker/bluespace(src)
/obj/item/storage/part_replacer/proc/play_rped_sound()
//Plays the sound for RPED exchanging or installing parts.
if(alt_sound && prob(3))
playsound(src, alt_sound, 40, 1)
else
playsound(src, primary_sound, 40, 1)
////////////////////////////////////////
// MARK: Stock parts
////////////////////////////////////////
/obj/item/stock_parts
name = "stock part"
desc = "What?"
gender = PLURAL
icon = 'icons/obj/stock_parts.dmi'
w_class = WEIGHT_CLASS_SMALL
var/rating = 1
usesound = 'sound/items/deconstruct.ogg'
//Rank 1
/obj/item/stock_parts/capacitor
name = "capacitor"
desc = "A basic capacitor used in the construction of a variety of devices."
icon_state = "capacitor"
item_state = "capacitor"
origin_tech = "powerstorage=1"
materials = list(MAT_METAL=50, MAT_GLASS=50)
/obj/item/stock_parts/scanning_module
name = "scanning module"
desc = "A compact, high resolution scanning module used in the construction of certain devices."
icon_state = "scan_module"
item_state = "scan_module"
origin_tech = "magnets=1"
materials = list(MAT_METAL=50, MAT_GLASS=20)
/obj/item/stock_parts/manipulator
name = "micro-manipulator"
desc = "A tiny little manipulator used in the construction of certain devices."
icon_state = "micro_mani"
item_state = "micro_mani"
origin_tech = "materials=1;programming=1"
materials = list(MAT_METAL=30)
/obj/item/stock_parts/micro_laser
name = "micro-laser"
desc = "A tiny laser used in certain devices."
icon_state = "micro_laser"
item_state = "micro_laser"
origin_tech = "magnets=1"
materials = list(MAT_METAL=10, MAT_GLASS=20)
/obj/item/stock_parts/matter_bin
name = "matter bin"
desc = "A container used to hold compressed matter awaiting re-construction."
icon_state = "matter_bin"
origin_tech = "materials=1"
materials = list(MAT_METAL=80)
//Rank 2
/obj/item/stock_parts/capacitor/adv
name = "advanced capacitor"
desc = "An advanced capacitor used in the construction of a variety of devices."
icon_state = "adv_capacitor"
item_state = "adv_capacitor"
origin_tech = "powerstorage=3"
rating = 2
materials = list(MAT_METAL=50, MAT_GLASS=50)
/obj/item/stock_parts/scanning_module/adv
name = "advanced scanning module"
icon_state = "adv_scan_module"
item_state = "adv_scan_module"
origin_tech = "magnets=3"
rating = 2
materials = list(MAT_METAL=50, MAT_GLASS=20)
/obj/item/stock_parts/manipulator/nano
name = "nano-manipulator"
icon_state = "nano_mani"
item_state = "nano_mani"
origin_tech = "materials=3;programming=2"
rating = 2
materials = list(MAT_METAL=30)
/obj/item/stock_parts/micro_laser/high
name = "high-power micro-laser"
icon_state = "high_micro_laser"
item_state = "high_micro_laser"
origin_tech = "magnets=3"
rating = 2
materials = list(MAT_METAL=10, MAT_GLASS=20)
/obj/item/stock_parts/matter_bin/adv
name = "advanced matter bin"
icon_state = "advanced_matter_bin"
item_state = "advanced_matter_bin"
origin_tech = "materials=3"
rating = 2
materials = list(MAT_METAL=80)
//Rating 3
/obj/item/stock_parts/capacitor/super
name = "super capacitor"
desc = "A super-high capacity capacitor used in the construction of a variety of devices."
icon_state = "super_capacitor"
item_state = "super_capacitor"
origin_tech = "powerstorage=4;engineering=4"
rating = 3
materials = list(MAT_METAL=50, MAT_GLASS=50)
/obj/item/stock_parts/scanning_module/phasic
name = "phasic scanning module"
desc = "A compact, high resolution phasic scanning module used in the construction of certain devices."
icon_state = "super_scan_module"
item_state = "super_scan_module"
origin_tech = "magnets=4;engineering=4"
rating = 3
materials = list(MAT_METAL=50, MAT_GLASS=20)
/obj/item/stock_parts/manipulator/pico
name = "pico-manipulator"
icon_state = "pico_mani"
item_state = "pico_mani"
origin_tech = "materials=4;programming=4;engineering=4"
rating = 3
materials = list(MAT_METAL=30)
/obj/item/stock_parts/micro_laser/ultra
name = "ultra-high-power micro-laser"
icon_state = "ultra_high_micro_laser"
item_state = "ultra_high_micro_laser"
origin_tech = "magnets=4;engineering=4"
rating = 3
materials = list(MAT_METAL=10, MAT_GLASS=20)
/obj/item/stock_parts/matter_bin/super
name = "super matter bin"
icon_state = "super_matter_bin"
item_state = "super_matter_bin"
origin_tech = "materials=4;engineering=4"
rating = 3
materials = list(MAT_METAL=80)
//Rating 4
/obj/item/stock_parts/capacitor/quadratic
name = "quadratic capacitor"
desc = "An ultra-high capacity capacitor used in the construction of a variety of devices."
icon_state = "quadratic_capacitor"
item_state = "quadratic_capacitor"
origin_tech = "powerstorage=5;materials=4;engineering=4"
rating = 4
materials = list(MAT_METAL=50, MAT_GLASS=50)
/obj/item/stock_parts/scanning_module/triphasic
name = "triphasic scanning module"
desc = "A compact, ultra resolution triphasic scanning module used in the construction of certain devices."
icon_state = "triphasic_scan_module"
item_state = "triphasic_scan_module"
origin_tech = "magnets=5;materials=4;engineering=4"
rating = 4
materials = list(MAT_METAL=50, MAT_GLASS=20)
/obj/item/stock_parts/manipulator/femto
name = "femto-manipulator"
icon_state = "femto_mani"
item_state = "femto_mani"
origin_tech = "materials=6;programming=4;engineering=4"
rating = 4
materials = list(MAT_METAL=30)
/obj/item/stock_parts/micro_laser/quadultra
name = "quad-ultra micro-laser"
icon_state = "quadultra_micro_laser"
item_state = "quadultra_micro_laser"
origin_tech = "magnets=5;materials=4;engineering=4"
rating = 4
materials = list(MAT_METAL=10, MAT_GLASS=20)
/obj/item/stock_parts/matter_bin/bluespace
name = "bluespace matter bin"
icon_state = "bluespace_matter_bin"
item_state = "bluespace_matter_bin"
origin_tech = "materials=6;programming=4;engineering=4"
rating = 4
materials = list(MAT_METAL=80)
@@ -1,186 +0,0 @@
/obj/item/storage/bible
name = "bible"
desc = "Apply to head repeatedly."
lefthand_file = 'icons/mob/inhands/religion_lefthand.dmi'
righthand_file = 'icons/mob/inhands/religion_righthand.dmi'
icon_state ="bible"
throw_speed = 1
throw_range = 5
resistance_flags = FIRE_PROOF
drop_sound = 'sound/items/handling/book_drop.ogg'
pickup_sound = 'sound/items/handling/book_pickup.ogg'
var/mob/affecting = null
var/deity_name = "Christ"
/// Is the sprite of this bible customisable
var/customisable = FALSE
/// Associative list of accociative lists of bible variants, used for the radial menu
var/static/list/bible_variants = list(
"Bible" = list("state" = "bible", "inhand" = "bible"),
"Koran" = list("state" = "koran", "inhand" = "koran"),
"Scrapbook" = list("state" = "scrapbook", "inhand" = "scrapbook"),
"Creeper" = list("state" = "creeper", "inhand" = "generic_bible"),
"White Bible" = list("state" = "white", "inhand" = "generic_bible"),
"Holy Light" = list("state" = "holylight", "inhand" = "generic_bible"),
"PlainRed" = list("state" = "athiest", "inhand" = "generic_bible"),
"Tome" = list("state" = "tome", "inhand" = "generic_bible"),
"The King in Yellow" = list("state" = "kingyellow", "inhand" = "kingyellow"),
"Ithaqua" = list("state" = "ithaqua", "inhand" = "ithaqua"),
"Scientology" = list("state" = "scientology", "inhand" = "scientology"),
"the bible melts" = list("state" = "melted", "inhand" = "melted"),
"Necronomicon" = list("state" = "necronomicon", "inhand" = "necronomicon"),
"Greentext" = list("state" = "greentext", "inhand" = "greentext"),
"Honkmother" = list("state" = "honk", "inhand" = "honk"),
"Silentfather" = list("state" = "mime", "inhand" = "mime"),
"Clockwork" = list("state" = "clock_bible", "inhand" = "clock_bible"),
"Nanotrasen" = list("state" = "nanotrasen", "inhand" = "nanotrasen")
)
/obj/item/storage/bible/suicide_act(mob/user)
user.visible_message("<span class='suicide'>[user] stares into [name] and attempts to transcend understanding of the universe!</span>")
user.dust()
return OBLITERATION
/obj/item/storage/bible/fart_act(mob/living/M)
if(QDELETED(M) || M.stat == DEAD)
return
M.visible_message("<span class='danger'>[M] farts on \the [name]!</span>")
M.visible_message("<span class='userdanger'>A mysterious force smites [M]!</span>")
M.suiciding = TRUE
do_sparks(3, 1, M)
M.gib()
return TRUE // Don't run the fart emote
/obj/item/storage/bible/booze
desc = "To be applied to the head repeatedly."
/obj/item/storage/bible/booze/populate_contents()
new /obj/item/reagent_containers/drinks/bottle/beer(src)
new /obj/item/reagent_containers/drinks/bottle/beer(src)
new /obj/item/stack/spacecash(src)
new /obj/item/stack/spacecash(src)
new /obj/item/stack/spacecash(src)
//BS12 EDIT
// All cult functionality moved to Null Rod
/obj/item/storage/bible/proc/bless(mob/living/carbon/M)
if(ishuman(M))
var/mob/living/carbon/human/H = M
H.heal_overall_damage(10, 10)
return
/obj/item/storage/bible/attack__legacy__attackchain(mob/living/M, mob/living/user)
add_attack_logs(user, M, "Hit with [src]")
if(!(ishuman(user) || SSticker) && SSticker.mode.name != "monkey")
to_chat(user, "<span class='warning'>You don't have the dexterity to do this!</span>")
return
if(!HAS_MIND_TRAIT(user, TRAIT_HOLY))
to_chat(user, "<span class='warning'>The book sizzles in your hands.</span>")
user.take_organ_damage(0, 10)
return
if(HAS_TRAIT(user, TRAIT_CLUMSY) && prob(50))
to_chat(user, "<span class='warning'>[src] slips out of your hand and hits your head.</span>")
user.take_organ_damage(10)
user.Paralyse(40 SECONDS)
return
if(M.stat != DEAD && ishuman(M))
var/mob/living/carbon/human/H = M
if(prob(60))
bless(H)
H.visible_message("<span class='danger'>[user] heals [H == user ? "[user.p_themselves()]" : "[H]"] with the power of [deity_name]!</span>",
"<span class='danger'>May the power of [deity_name] compel you to be healed!</span>")
playsound(loc, "punch", 25, TRUE, -1)
else
M.adjustBrainLoss(10)
to_chat(M, "<span class='warning'>You feel dumber.</span>")
H.visible_message("<span class='danger'>[user] beats [H == user ? "[user.p_themselves()]" : "[H]"] over the head with [src]!</span>")
playsound(src.loc, "punch", 25, TRUE, -1)
else
M.visible_message("<span class='danger'>[user] smacks [M]'s lifeless corpse with [src].</span>")
playsound(src.loc, "punch", 25, TRUE, -1)
/obj/item/storage/bible/afterattack__legacy__attackchain(atom/target, mob/user, proximity, params)
if(!proximity)
return
if(isfloorturf(target))
to_chat(user, "<span class='notice'>You hit the floor with the bible.</span>")
if(HAS_MIND_TRAIT(user, TRAIT_HOLY))
for(var/obj/O in target)
O.cult_reveal()
if(istype(target, /obj/machinery/door/airlock))
to_chat(user, "<span class='notice'>You hit the airlock with the bible.</span>")
if(HAS_MIND_TRAIT(user, TRAIT_HOLY))
var/obj/airlock = target
airlock.cult_reveal()
if(HAS_MIND_TRAIT(user, TRAIT_HOLY) && target.reagents)
if(target.reagents.has_reagent("water")) //blesses all the water in the holder
to_chat(user, "<span class='notice'>You bless [target].</span>")
var/water2holy = target.reagents.get_reagent_amount("water")
target.reagents.del_reagent("water")
target.reagents.add_reagent("holywater", water2holy)
if(target.reagents.has_reagent("unholywater")) //yeah yeah, copy pasted code - sue me
to_chat(user, "<span class='notice'>You purify [target].</span>")
var/unholy2clean = target.reagents.get_reagent_amount("unholywater")
target.reagents.del_reagent("unholywater")
target.reagents.add_reagent("holywater", unholy2clean)
/obj/item/storage/bible/attack_self__legacy__attackchain(mob/user)
. = ..()
if(!customisable || !HAS_MIND_TRAIT(user, TRAIT_HOLY))
return
var/list/skins = list()
for(var/I in bible_variants)
var/icons = bible_variants[I] // Get the accociated list
var/image/bible_image = image('icons/obj/storage.dmi', icon_state = icons["state"])
skins[I] = bible_image
var/choice = show_radial_menu(user, src, skins, null, 40, CALLBACK(src, PROC_REF(radial_check), user), TRUE)
if(!choice || !radial_check(user))
return
var/choice_icons = bible_variants[choice]
icon_state = choice_icons["state"]
item_state = choice_icons["inhand"]
customisable = FALSE
// Carpet symbol icons are currently broken, so commented out until it's fixed
/*var/carpet_dir
switch(choice)
if("Bible")
carpet_dir = 2
if("Koran")
carpet_dir = 4
if("Scientology")
carpet_dir = 8
if(carpet_dir)
for(var/area/station/service/chapel/main/A in world)
for(var/turf/T in A.contents)
if(T.icon_state == "carpetsymbol")
T.dir = carpet_dir*/
SSblackbox.record_feedback("text", "religion_book", 1, "[choice]", 1)
if(SSticker)
SSticker.Bible_name = name
SSticker.Bible_icon_state = icon_state
SSticker.Bible_item_state = item_state
/obj/item/storage/bible/proc/radial_check(mob/user)
if(!HAS_MIND_TRAIT(user, TRAIT_HOLY) || !ishuman(user))
return FALSE
var/mob/living/carbon/human/H = user
if(!src || !H.is_in_hands(src) || H.incapacitated())
return FALSE
return TRUE
/obj/item/storage/bible/syndi
name = "suspicious bible"
desc = "For treading the line between cultist, contraband, and a hostile corporation."
icon_state = "syndi"
@@ -1,500 +0,0 @@
/*
* The 'fancy' path is for objects like donut boxes that show how many items are in the storage item on the sprite itself
* .. Sorry for the shitty path name, I couldnt think of a better one.
*
* WARNING: var/icon_type is used for both examine text and sprite name. Please look at the procs below and adjust your sprite names accordingly
* TODO: Cigarette boxes should be ported to this standard
*
* Contains:
* Donut Box
* Egg Box
* Candle Box
* Crayon Box
* Cigarette Box
* Vial Box
* Aquatic Starter Kit
*/
/obj/item/storage/fancy
icon = 'icons/obj/food/containers.dmi'
resistance_flags = FLAMMABLE
var/icon_type
/obj/item/storage/fancy/update_icon_state()
icon_state = "[icon_type]box[length(contents)]"
/obj/item/storage/fancy/examine(mob/user)
. = ..()
. += fancy_storage_examine(user)
/obj/item/storage/fancy/proc/fancy_storage_examine(mob/user)
. = list()
if(in_range(user, src))
var/len = LAZYLEN(contents)
if(len <= 0)
. += "There are no [icon_type]s left in the box."
else if(len == 1)
. += "There is one [icon_type] left in the box."
else
. += "There are [length(contents)] [icon_type]s in the box."
/obj/item/storage/fancy/remove_from_storage(obj/item/I, atom/new_location)
if(!istype(I))
return FALSE
update_icon()
return ..()
// MARK: Donut Box
/obj/item/storage/fancy/donut_box
name = "donut box"
desc = "\"To do, or do nut, the choice is obvious.\""
icon_type = "donut"
icon_state = "donutbox"
storage_slots = 6
can_hold = list(/obj/item/food/donut)
foldable = /obj/item/stack/sheet/cardboard
foldable_amt = 1
/obj/item/storage/fancy/donut_box/update_overlays()
. = ..()
for(var/I = 1 to length(contents))
var/obj/item/food/donut/donut = contents[I]
var/icon/new_donut_icon = icon('icons/obj/food/containers.dmi', "[(I - 1)]donut[donut.donut_sprite_type]")
. += new_donut_icon
/obj/item/storage/fancy/donut_box/update_icon_state()
return
/obj/item/storage/fancy/donut_box/populate_contents()
for(var/I in 1 to storage_slots)
new /obj/item/food/donut(src)
update_icon(UPDATE_OVERLAYS)
/obj/item/storage/fancy/donut_box/empty/populate_contents()
update_icon(UPDATE_OVERLAYS)
return
/obj/item/storage/fancy/donut_box/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(isdrone(user) && !length(contents))
C.stored_comms["wood"] += 1
qdel(src)
return TRUE
return ..()
// MARK: Egg Box
/obj/item/storage/fancy/egg_box
icon_state = "eggbox"
icon_type = "egg"
item_state = "eggbox"
name = "egg box"
storage_slots = 12
can_hold = list(/obj/item/food/egg)
/obj/item/storage/fancy/egg_box/populate_contents()
for(var/I in 1 to storage_slots)
new /obj/item/food/egg(src)
// MARK: Candle Box
/obj/item/storage/fancy/candle_box
name = "Candle pack"
desc = "A pack of red candles."
icon = 'icons/obj/candle.dmi'
icon_state = "candlebox0"
icon_type = "candle"
item_state = "candlebox5"
storage_slots = 5
throwforce = 2
slot_flags = ITEM_SLOT_BELT
/obj/item/storage/fancy/candle_box/Initialize(mapload)
. = ..()
update_icon(UPDATE_ICON_STATE)
/obj/item/storage/fancy/candle_box/full/populate_contents()
for(var/I in 1 to storage_slots)
new /obj/item/candle(src)
/obj/item/storage/fancy/candle_box/eternal
name = "Eternal Candle pack"
desc = "A pack of red candles made with a special wax."
/obj/item/storage/fancy/candle_box/eternal/populate_contents()
for(var/I in 1 to storage_slots)
new /obj/item/candle/eternal(src)
// MARK: Crayon Box
/obj/item/storage/fancy/crayons
name = "box of crayons"
desc = "A box of crayons for all your rune drawing needs."
icon = 'icons/obj/crayons.dmi'
icon_state = "crayonbox"
w_class = WEIGHT_CLASS_SMALL
storage_slots = 8
icon_type = "crayon"
can_hold = list(
/obj/item/toy/crayon
)
/obj/item/storage/fancy/crayons/populate_contents()
new /obj/item/toy/crayon/white(src)
new /obj/item/toy/crayon/red(src)
new /obj/item/toy/crayon/orange(src)
new /obj/item/toy/crayon/yellow(src)
new /obj/item/toy/crayon/green(src)
new /obj/item/toy/crayon/blue(src)
new /obj/item/toy/crayon/purple(src)
new /obj/item/toy/crayon/black(src)
update_icon()
/obj/item/storage/fancy/crayons/update_overlays()
. = ..()
. += image('icons/obj/crayons.dmi',"crayonbox")
for(var/obj/item/toy/crayon/crayon in contents)
. += image('icons/obj/crayons.dmi', crayon.dye_color)
/obj/item/storage/fancy/crayons/attackby__legacy__attackchain(obj/item/I, mob/user, params)
if(istype(I, /obj/item/toy/crayon))
var/obj/item/toy/crayon/C = I
switch(C.dye_color)
if("mime")
to_chat(usr, "This crayon is too sad to be contained in this box.")
return
if("rainbow")
to_chat(usr, "This crayon is too powerful to be contained in this box.")
return
..()
/*
* Matches Box
*/
/obj/item/storage/fancy/matches
name = "matchbox"
desc = "A small box of Almost But Not Quite Plasma Premium Matches."
icon = 'icons/obj/cigarettes.dmi'
icon_state = "matchbox"
item_state = "matchbox"
base_icon_state = "matchbox"
storage_slots = 10
w_class = WEIGHT_CLASS_TINY
max_w_class = WEIGHT_CLASS_TINY
slot_flags = ITEM_SLOT_BELT
drop_sound = 'sound/items/handling/matchbox_drop.ogg'
pickup_sound = 'sound/items/handling/matchbox_pickup.ogg'
can_hold = list(/obj/item/match)
/obj/item/storage/fancy/matches/populate_contents()
for(var/I in 1 to storage_slots)
new /obj/item/match(src)
/obj/item/storage/fancy/matches/attackby__legacy__attackchain(obj/item/match/W, mob/user, params)
if(istype(W, /obj/item/match) && !W.lit)
W.matchignite()
playsound(user.loc, 'sound/goonstation/misc/matchstick_light.ogg', 50, TRUE)
return
/obj/item/storage/fancy/matches/update_icon_state()
. = ..()
switch(length(contents))
if(10)
icon_state = base_icon_state
if(5 to 9)
icon_state = "[base_icon_state]_almostfull"
if(1 to 4)
icon_state = "[base_icon_state]_almostempty"
if(0)
icon_state = "[base_icon_state]_e"
// MARK: Cigarette Pack
/obj/item/storage/fancy/cigarettes
name = "generic cigarette packet"
desc = "An abstract brand of cigarette that should not exist. Make a GitHub report if you see this."
icon = 'icons/obj/cigarettes.dmi'
icon_state = "robust_packet"
item_state = "robust_packet"
belt_icon = "patch_pack"
w_class = WEIGHT_CLASS_SMALL
slot_flags = ITEM_SLOT_BELT
storage_slots = 6
max_combined_w_class = 6
can_hold = list(/obj/item/clothing/mask/cigarette,
/obj/item/lighter,
/obj/item/match)
cant_hold = list(/obj/item/clothing/mask/cigarette/cigar,
/obj/item/clothing/mask/cigarette/pipe,
/obj/item/lighter/zippo)
icon_type = "cigarette"
var/cigarette_slogan = "The preferred brand of coders and developers."
var/cigarette_type = /obj/item/clothing/mask/cigarette
/obj/item/storage/fancy/cigarettes/examine(mob/user)
. = ..()
if(cigarette_slogan)
. += "<span class='notice'>\"[cigarette_slogan]\"</span>"
/obj/item/storage/fancy/cigarettes/populate_contents()
for(var/I in 1 to storage_slots)
new cigarette_type(src)
/obj/item/storage/fancy/cigarettes/update_icon_state()
icon_state = "[initial(icon_state)]_[length(contents)]"
/obj/item/storage/fancy/cigarettes/attack__legacy__attackchain(mob/living/carbon/M, mob/living/user)
if(!ismob(M))
return
if(istype(M) && user.zone_selected == "mouth" && length(contents) > 0 && !M.wear_mask)
var/got_cig = FALSE
for(var/num in 1 to length(contents))
var/obj/item/I = contents[num]
if(istype(I, /obj/item/clothing/mask/cigarette))
var/obj/item/clothing/mask/cigarette/C = I
M.equip_to_slot_if_possible(C, ITEM_SLOT_MASK)
if(M != user)
user.visible_message(
"<span class='notice'>[user] takes \a [C.name] out of [src] and gives it to [M].</span>",
"<span class='notice'>You take \a [C.name] out of [src] and give it to [M].</span>"
)
else
to_chat(user, "<span class='notice'>You take \a [C.name] out of the pack.</span>")
update_icon()
got_cig = TRUE
break
if(!got_cig)
to_chat(user, "<span class='warning'>There are no smokables in the pack!</span>")
else
..()
/obj/item/storage/fancy/cigarettes/can_be_inserted(obj/item/W, stop_messages = FALSE)
if(istype(W, /obj/item/match))
var/obj/item/match/M = W
if(M.lit)
if(!stop_messages)
to_chat(usr, "<span class='notice'>Putting a lit [W] in [src] probably isn't a good idea.</span>")
return FALSE
if(istype(W, /obj/item/lighter))
var/obj/item/lighter/L = W
if(L.lit)
if(!stop_messages)
to_chat(usr, "<span class='notice'>Putting [W] in [src] while lit probably isn't a good idea.</span>")
return FALSE
//if we get this far, handle the insertion checks as normal
. = ..()
/obj/item/storage/fancy/cigarettes/decompile_act(obj/item/matter_decompiler/C, mob/user)
if(isdrone(user) && !length(contents))
C.stored_comms["wood"] += 1
qdel(src)
return TRUE
return ..()
/obj/item/storage/fancy/cigarettes/cigpack_carp
name = "\improper Carp Classic packet"
desc = "Smoked mainly by spacers. The somewhat fishy notes are an acquired taste. \
Has a light, low-tar smoke specifically designed to reduce stress on scrubber systems."
icon_state = "carp_packet"
item_state = "carp_packet"
cigarette_slogan = "Carp smokers would rather bite you than switch, since 2313."
/obj/item/storage/fancy/cigarettes/dromedaryco
name = "\improper DromedaryCo packet"
desc = "An infamous brand, DromedaryCo cigarettes are unfiltered, tarry, and have a very harsh flavour. \
Not for beginner smokers. Enjoyed mainly by gruff types with equally gruff voices."
icon_state = "D_packet"
item_state = "D_packet"
cigarette_slogan = "Wouldn't a slow death make a change?"
/obj/item/storage/fancy/cigarettes/cigpack_random
name ="\improper Embellished Enigma packet"
desc = "True to the name, Enigmas are impossible to pin down. \
No two cigarettes are alike as each one is infused with unique flavours and substances, so every time is just like your first time."
icon_state = "enigma_packet"
item_state = "enigma_packet"
cigarette_slogan = "For the true connoisseur of exotic flavors."
cigarette_type = /obj/item/clothing/mask/cigarette/random
/obj/item/storage/fancy/cigarettes/cigpack_random/examine(mob/user)
. = ..()
. += "<span class = 'warning'>Warning: Not all substances used have undergone regulatory testing, smoke at your own risk. \
The Embellished Enigma Tobacco Company does not accept liability for proper or negligent use of its products. Consult your doctor before use.</span>"
/obj/item/storage/fancy/cigarettes/cigpack_midori
name = "\improper Midori Tabako packet"
desc = "Whilst you cannot decipher what the strange runes on the packet say, it bears the unmistakable scent of cannabis."
icon_state = "midori_packet"
item_state = "midori_packet"
cigarette_slogan = ""
cigarette_type = /obj/item/clothing/mask/cigarette/rollie
/obj/item/storage/fancy/cigarettes/cigpack_our_brand
name = "\improper Our Brand packet" // This brand name is an obscure reference to The Master and Margarita by Ivan Bezdomny.
desc = "The one, official brand of cigarette manufactured by the Vostran Iron Republic - one of the main constitient nations of the USSP. \
Exported across the known Orion Spur by members of the USSP's trading bloc and vendors affiliated with the Nian Merchant Guild. \
The flavour is acrid, the smoke is thin and wispy, yet harsh on the throat. The only redeeming features are the high nicotine content and the low price."
icon_state = "our_brand_packet"
item_state = "our_brand_packet"
cigarette_slogan = "Smoke, for the Union!"
/obj/item/storage/fancy/cigarettes/cigpack_robust
name = "\improper Robust packet"
desc = "Nanotrasen's in-house brand of cigarettes. Cheap quality, wispy smoke, has a somewhat harsh flavour."
cigarette_slogan = "Smoked by the robust."
/obj/item/storage/fancy/cigarettes/cigpack_robustgold
name = "\improper Robust Gold packet"
desc = "Nanotrasen's premium cigarette offering. Has a smooth, drawn-out flavour and a dense smoke. Contains real gold."
icon_state = "robust_g_packet"
item_state = "robust_g_packet"
cigarette_slogan = "Smoked by the <b>truly</b> robust."
cigarette_type = /obj/item/clothing/mask/cigarette/robustgold
/obj/item/storage/fancy/cigarettes/cigpack_candy
name = "\improper Robust Junior packet"
desc = "A packet of nicotine-free* candy cigarettes, manufactured by Robust Tobacco."
cigarette_slogan = "Unsure about smoking? Want to bring your children safely into the family tradition? Look no more with this special packet! Includes 100% nicotine-free* candy cigarettes."
cigarette_type = /obj/item/clothing/mask/cigarette/candy
/obj/item/storage/fancy/cigarettes/cigpack_candy/examine(mob/user)
. = ..()
. += "<span class = 'warning'>*Warning: Do not expose to high temperatures or naked flames, contains additives that will form nicotine at high temperatures.</span>"
/obj/item/storage/fancy/cigarettes/cigpack_shadyjims
name ="\improper Shady Jim's Super Slims packet"
desc = "Despite the doubious appearance, these cigarettes do exactly what they say on the box. The smoke tastes like cheap berry juice and battery acid, with a bitter chemical aftertaste."
icon_state = "shady_jim_packet"
item_state = "shady_jim_packet"
cigarette_slogan = "Is your weight slowing you down? Having trouble running away from gravitational singularities? Can't stop stuffing your mouth? \
Smoke Shady Jim's Super Slims and watch all that fat burn away. Guaranteed results!"
cigarette_type = /obj/item/clothing/mask/cigarette/shadyjims
/obj/item/storage/fancy/cigarettes/cigpack_solar_rays
name = "\improper Solar Rays packet"
desc = "A popular brand within the Trans-Solar Federation, they have a smooth, slightly cinnamon flavour. \
Whilst not actually state-owned, these cigarettes lean heavily into patriotic marketing, and are included in federal ration packs as a morale booster."
icon_state = "solar_packet"
item_state = "solar_packet"
cigarette_slogan = "Smoked by true patriots."
/obj/item/storage/fancy/cigarettes/cigpack_uplift
name = "\improper Uplift Smooth packet"
desc = "One of the most popular brands in the Orion Sector, flavoured with menthol to give a smooth cooling sensation with every puff."
icon_state = "uplift_packet"
item_state = "uplift_packet"
cigarette_slogan = "Sit back and relax with the soft cooling embrace that only an Uplift can provide."
cigarette_type = /obj/item/clothing/mask/cigarette/menthol
/obj/item/storage/fancy/cigarettes/cigpack_med
name = "medical marijuana packet"
desc = "A prescription packet containing six fully legal medical marijuana cigarettes. \
Made using a strain of cannabis engineered to maximise CBD content and eliminate THC, much to the chagrin of stoners everywhere."
icon_state = "med_packet"
item_state = "med_packet"
cigarette_slogan = "All the medical benefits, with none of the high!"
cigarette_type = /obj/item/clothing/mask/cigarette/medical_marijuana
/obj/item/storage/fancy/cigarettes/cigpack_syndicate
name = "suspicious cigarette packet"
desc = "An obscure brand of evil-looking cigarettes. Smells like Donk pockets."
icon_state = "syndie_packet"
item_state = "syndie_packet"
cigarette_slogan = "Strong flavour, dense smoke, infused with omnizine."
cigarette_type = /obj/item/clothing/mask/cigarette/syndicate
/obj/item/storage/fancy/rollingpapers
name = "rolling paper pack"
desc = "A pack of Nanotrasen brand rolling papers."
w_class = WEIGHT_CLASS_TINY
icon = 'icons/obj/cigarettes.dmi'
icon_state = "cig_paper_pack"
item_state = "cig_paper_pack"
storage_slots = 10
icon_type = "rolling paper"
can_hold = list(/obj/item/rollingpaper)
/obj/item/storage/fancy/rollingpapers/update_icon_state()
return
/obj/item/storage/fancy/rollingpapers/populate_contents()
for(var/I in 1 to storage_slots)
new /obj/item/rollingpaper(src)
/obj/item/storage/fancy/rollingpapers/update_overlays()
. = ..()
if(!length(contents))
. += "[icon_state]_empty"
// MARK: Vial Box
/obj/item/storage/fancy/vials
icon = 'icons/obj/vialbox.dmi'
icon_state = "vialbox6"
icon_type = "vial"
name = "vial storage box"
storage_slots = 6
can_hold = list(/obj/item/reagent_containers/glass/beaker/vial)
/obj/item/storage/fancy/vials/populate_contents()
for(var/I in 1 to storage_slots)
new /obj/item/reagent_containers/glass/beaker/vial(src)
return
/obj/item/storage/lockbox/vials
name = "secure vial storage box"
desc = "A locked box for keeping things away from children."
icon = 'icons/obj/vialbox.dmi'
icon_state = "vialbox0"
can_hold = list(/obj/item/reagent_containers/glass/bottle)
storage_slots = 6
req_access = list(ACCESS_VIROLOGY)
/obj/item/storage/lockbox/vials/Initialize(mapload)
. = ..()
update_icon()
/obj/item/storage/lockbox/vials/update_icon_state()
icon_state = "vialbox[length(contents)]"
cut_overlays()
/obj/item/storage/lockbox/vials/update_overlays()
. = ..()
if(!broken)
. += "led[locked]"
if(locked)
. += "cover"
else
. += "ledb"
/obj/item/storage/lockbox/vials/attackby__legacy__attackchain(obj/item/I, mob/user, params)
..()
update_icon()
/obj/item/storage/lockbox/vials/zombie_cure
name = "secure vial storage box - 'Anti-Plague Sequences'"
/obj/item/storage/lockbox/vials/zombie_cure/populate_contents()
new /obj/item/reagent_containers/glass/bottle/zombiecure1(src)
new /obj/item/reagent_containers/glass/bottle/zombiecure2(src)
new /obj/item/reagent_containers/glass/bottle/zombiecure3(src)
new /obj/item/reagent_containers/glass/bottle/zombiecure4(src)
// MARK: Aquatic Starter Kit
/obj/item/storage/firstaid/aquatic_kit
name = "aquatic starter kit"
desc = "It's a starter kit box for an aquarium."
icon_state = "AquaticKit"
med_bot_skin = "fish"
/obj/item/storage/firstaid/aquatic_kit/full
desc = "It's a starter kit for an aquarium; includes 1 tank brush, 1 egg scoop, 1 fish net, 1 container of fish food and 1 fish bag."
/obj/item/storage/firstaid/aquatic_kit/full/populate_contents()
new /obj/item/egg_scoop(src)
new /obj/item/fish_net(src)
new /obj/item/tank_brush(src)
new /obj/item/fishfood(src)
new /obj/item/storage/bag/fish(src)
@@ -1,437 +0,0 @@
/* First aid storage
* Contains:
* First Aid Kits
* Pill Bottles
* Dice Pack (in a pill bottle)
*/
/*
* First Aid Kits
*/
/obj/item/storage/firstaid
name = "generic first-aid kit"
desc = "If you can see this, make a bug report on GitHub, something went wrong!"
icon_state = "genericfirstaid"
throw_range = 8
req_one_access =list(ACCESS_MEDICAL, ACCESS_ROBOTICS) //Access and treatment are utilized for medbots.
var/treatment_brute = "salglu_solution"
var/treatment_oxy = "salbutamol"
var/treatment_fire = "salglu_solution"
var/treatment_tox = "charcoal"
var/treatment_virus = "spaceacillin"
var/med_bot_skin = null
var/syndicate_aligned = FALSE
var/robot_arm // This is for robot construction
/obj/item/storage/firstaid/regular
name = "first-aid kit"
desc = "A general medical kit that contains medical patches for both brute damage and burn damage. Also contains an epinephrine syringe for emergency use and a health analyzer."
icon_state = "firstaid"
/obj/item/storage/firstaid/regular/populate_contents()
new /obj/item/reagent_containers/patch/styptic(src)
new /obj/item/reagent_containers/patch/styptic(src)
new /obj/item/reagent_containers/pill/salicylic(src)
new /obj/item/reagent_containers/patch/silver_sulf(src)
new /obj/item/reagent_containers/patch/silver_sulf(src)
new /obj/item/healthanalyzer(src)
new /obj/item/reagent_containers/hypospray/autoinjector/epinephrine(src)
/obj/item/storage/firstaid/regular/empty/populate_contents()
return
/obj/item/storage/firstaid/regular/doctor
desc = "A medical kit designed for Nanotrasen medical personnel."
/obj/item/storage/firstaid/regular/doctor/populate_contents()
new /obj/item/reagent_containers/applicator/brute(src)
new /obj/item/reagent_containers/applicator/burn(src)
new /obj/item/reagent_containers/patch/styptic(src)
new /obj/item/reagent_containers/patch/silver_sulf(src)
new /obj/item/reagent_containers/pill/salicylic(src)
new /obj/item/healthanalyzer/advanced(src)
new /obj/item/reagent_containers/hypospray/autoinjector/epinephrine(src)
/obj/item/storage/firstaid/fire
name = "fire first-aid kit"
desc = "A medical kit that contains several medical patches and pills for treating burns. Contains one epinephrine syringe for emergency use and a health analyzer."
icon_state = "ointment"
item_state = "firstaid-ointment"
med_bot_skin = "ointment"
/obj/item/storage/firstaid/fire/Initialize(mapload)
. = ..()
icon_state = pick("ointment", "firefirstaid")
/obj/item/storage/firstaid/fire/populate_contents()
new /obj/item/reagent_containers/applicator/burn(src)
new /obj/item/reagent_containers/patch/silver_sulf/small(src)
new /obj/item/healthanalyzer(src)
new /obj/item/reagent_containers/hypospray/autoinjector/epinephrine(src)
new /obj/item/reagent_containers/pill/salicylic(src)
/obj/item/storage/firstaid/fire/empty/populate_contents()
return
/obj/item/storage/firstaid/toxin
name = "toxin first aid kit"
desc = "A medical kit designed to counter poisoning by common toxins. Contains three pills and syringes, and a health analyzer to determine the health of the patient."
icon_state = "antitoxin"
item_state = "firstaid-toxin"
med_bot_skin = "tox"
/obj/item/storage/firstaid/toxin/Initialize(mapload)
. = ..()
icon_state = pick("antitoxin", "antitoxfirstaid", "antitoxfirstaid2")
/obj/item/storage/firstaid/toxin/populate_contents()
for(var/I in 1 to 3)
new /obj/item/reagent_containers/syringe/charcoal(src)
new /obj/item/reagent_containers/pill/charcoal(src)
new /obj/item/healthanalyzer(src)
/obj/item/storage/firstaid/toxin/empty/populate_contents()
return
/obj/item/storage/firstaid/o2
name = "oxygen deprivation first aid kit"
desc = "A first aid kit that contains four pills of salbutamol, which is able to counter injuries caused by suffocation. Also contains a health analyzer to determine the health of the patient."
icon_state = "o2"
item_state = "firstaid-o2"
med_bot_skin = "o2"
/obj/item/storage/firstaid/o2/populate_contents()
new /obj/item/reagent_containers/pill/salbutamol(src)
new /obj/item/reagent_containers/pill/salbutamol(src)
new /obj/item/reagent_containers/pill/salbutamol(src)
new /obj/item/reagent_containers/pill/salbutamol(src)
new /obj/item/healthanalyzer(src)
/obj/item/storage/firstaid/o2/empty/populate_contents()
return
/obj/item/storage/firstaid/brute
name = "brute trauma treatment kit"
desc = "A medical kit that contains several medical patches and pills for treating brute injuries. Contains one epinephrine syringe for emergency use and a health analyzer."
icon_state = "brute"
item_state = "firstaid-brute"
med_bot_skin = "brute"
/obj/item/storage/firstaid/brute/Initialize(mapload)
. = ..()
icon_state = pick("brute", "brute2")
/obj/item/storage/firstaid/brute/populate_contents()
new /obj/item/reagent_containers/applicator/brute(src)
new /obj/item/reagent_containers/patch/styptic/small(src)
new /obj/item/healthanalyzer(src)
new /obj/item/reagent_containers/hypospray/autoinjector/epinephrine(src)
new /obj/item/stack/medical/bruise_pack(src)
/obj/item/storage/firstaid/brute/empty/populate_contents()
return
/obj/item/storage/firstaid/adv
name = "advanced first-aid kit"
desc = "Contains advanced medical treatments."
icon_state = "advfirstaid"
item_state = "firstaid-advanced"
med_bot_skin = "adv"
/obj/item/storage/firstaid/adv/populate_contents()
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/stack/medical/bruise_pack/advanced(src)
new /obj/item/stack/medical/bruise_pack/advanced(src)
new /obj/item/stack/medical/ointment/advanced(src)
new /obj/item/stack/medical/ointment/advanced(src)
new /obj/item/reagent_containers/hypospray/autoinjector/epinephrine(src)
new /obj/item/healthanalyzer(src)
/obj/item/storage/firstaid/adv/empty/populate_contents()
return
/obj/item/storage/firstaid/machine
name = "machine repair kit"
desc = "A kit that contains supplies to repair IPCs on the go."
icon_state = "machinefirstaid"
item_state = "firstaid-machine"
med_bot_skin = "machine"
/obj/item/storage/firstaid/machine/populate_contents()
new /obj/item/weldingtool/mini(src)
new /obj/item/stack/cable_coil(src)
new /obj/item/stack/cable_coil(src)
new /obj/item/stack/cable_coil(src)
new /obj/item/robotanalyzer(src)
/obj/item/storage/firstaid/machine/empty/populate_contents()
return
/obj/item/storage/firstaid/tactical
name = "first-aid kit"
desc = "I hope you've got insurance."
icon_state = "bezerk"
treatment_oxy = "perfluorodecalin"
treatment_brute = "bicaridine"
treatment_fire = "kelotane"
req_one_access = list(ACCESS_SYNDICATE)
med_bot_skin = "bezerk"
syndicate_aligned = TRUE
/obj/item/storage/firstaid/tactical/populate_contents()
new /obj/item/reagent_containers/hypospray/combat(src)
new /obj/item/reagent_containers/applicator/dual/syndi(src) // Because you ain't got no time to look at what damage dey taking yo
new /obj/item/reagent_containers/hypospray/autoinjector/emergency_nuclear(src)
new /obj/item/reagent_containers/hypospray/autoinjector/emergency_nuclear(src)
new /obj/item/storage/pill_bottle/painkillers(src)
new /obj/item/clothing/glasses/hud/health/night(src)
new /obj/item/healthanalyzer/advanced(src)
/obj/item/storage/firstaid/tactical/empty/populate_contents()
return
/obj/item/storage/firstaid/surgery
name = "field surgery kit"
desc = "A kit for surgery in the field."
icon_state = "duffel-med"
lefthand_file = 'icons/mob/inhands/clothing_lefthand.dmi'
righthand_file = 'icons/mob/inhands/clothing_righthand.dmi'
max_w_class = WEIGHT_CLASS_BULKY
max_combined_w_class = 21
storage_slots = 10
can_hold = list(/obj/item/roller,/obj/item/bonesetter,/obj/item/bonegel, /obj/item/scalpel, /obj/item/hemostat,
/obj/item/cautery, /obj/item/retractor, /obj/item/fix_o_vein, /obj/item/surgicaldrill, /obj/item/circular_saw)
/obj/item/storage/firstaid/surgery/populate_contents()
new /obj/item/roller(src)
new /obj/item/bonesetter(src)
new /obj/item/bonegel(src)
new /obj/item/scalpel(src)
new /obj/item/hemostat(src)
new /obj/item/cautery(src)
new /obj/item/retractor(src)
new /obj/item/fix_o_vein(src)
new /obj/item/surgicaldrill(src)
new /obj/item/circular_saw(src)
/obj/item/storage/firstaid/ert
name = "ert first-aid kit"
desc = "A medical kit used by Nanotrasen emergency response team personnel."
icon_state = "bezerk"
med_bot_skin = "bezerk"
/obj/item/storage/firstaid/ert/populate_contents()
new /obj/item/healthanalyzer/advanced(src)
new /obj/item/stack/medical/splint(src)
new /obj/item/reagent_containers/applicator/dual(src)
new /obj/item/stack/medical/ointment/advanced(src)
new /obj/item/stack/medical/ointment/advanced(src)
new /obj/item/stack/medical/bruise_pack/advanced(src)
new /obj/item/stack/medical/bruise_pack/advanced(src)
/obj/item/storage/firstaid/ert_amber
name = "amber ert first-aid kit"
desc = "A medical kit used by Amber level emergency response team personnel."
icon_state = "firstaid"
/obj/item/storage/firstaid/ert_amber/populate_contents()
new /obj/item/healthanalyzer/advanced(src)
new /obj/item/reagent_containers/applicator/brute(src)
new /obj/item/reagent_containers/applicator/burn(src)
new /obj/item/stack/medical/bruise_pack/advanced(src)
new /obj/item/stack/medical/ointment/advanced(src)
new /obj/item/storage/pill_bottle/ert_amber(src)
new /obj/item/storage/pill_bottle/patch_pack/ert_amber(src)
/obj/item/storage/firstaid/fake_tactical
name = "tactical first-aid kit"
desc = "I hope you've got insurance. The paint is still wet."
icon_state = "bezerk"
med_bot_skin = "bezerk"
/obj/item/storage/firstaid/fake_tactical/populate_contents()
return
/*
* Pill Bottles
*/
/obj/item/storage/pill_bottle
name = "pill bottle"
desc = "It's an airtight container for storing medication."
icon_state = "pill_canister"
icon = 'icons/obj/chemical.dmi'
item_state = "contsolid"
belt_icon = "pill_bottle"
use_sound = "pillbottle"
w_class = WEIGHT_CLASS_SMALL
can_hold = list(/obj/item/reagent_containers/pill)
cant_hold = list(/obj/item/reagent_containers/patch)
allow_quick_gather = TRUE
use_to_pickup = TRUE
storage_slots = 50
max_combined_w_class = 50
display_contents_with_number = TRUE
var/base_name = ""
var/label_text = ""
var/applying_meds = FALSE //To Prevent spam clicking and generating runtimes from apply a deleting pill multiple times.
var/rapid_intake_message = "unscrews the cap on the pill bottle and begins dumping the entire contents down their throat!"
var/rapid_post_instake_message = "downs the entire bottle of pills in one go!"
/// Whether to render a coloured wrapper overlay on the icon.
var/allow_wrap = TRUE
/// The color of the wrapper overlay.
var/wrapper_color = null
/// The icon state of the wrapper overlay.
var/wrapper_state = "pillbottle_wrap"
/obj/item/storage/pill_bottle/Initialize(mapload)
. = ..()
base_name = name
if(allow_wrap)
apply_wrap()
/obj/item/storage/pill_bottle/proc/apply_wrap()
if(wrapper_color)
overlays.Cut()
var/image/I = image(icon, wrapper_state)
I.color = wrapper_color
overlays += I
/obj/item/storage/pill_bottle/attack__legacy__attackchain(mob/M, mob/user)
if(iscarbon(M) && length(contents))
if(applying_meds)
to_chat(user, "<span class='warning'>You are already applying meds.</span>")
return
applying_meds = TRUE
for(var/obj/item/reagent_containers/P in contents)
if(P.mob_act(M, user))
applying_meds = FALSE
else
applying_meds = FALSE
break
else
return ..()
/obj/item/storage/pill_bottle/ert_red
wrapper_color = COLOR_NT_RED
/obj/item/storage/pill_bottle/ert_red/populate_contents()
for(var/I in 1 to 6)
new /obj/item/reagent_containers/pill/pentetic(src)
new /obj/item/reagent_containers/pill/ironsaline(src)
new /obj/item/reagent_containers/pill/salicylic(src)
new /obj/item/reagent_containers/pill/mannitol(src)
/obj/item/storage/pill_bottle/ert_amber
wrapper_color = COLOR_ORANGE
/obj/item/storage/pill_bottle/ert_amber/populate_contents()
for(var/I in 1 to 6)
new /obj/item/reagent_containers/pill/salbutamol(src)
new /obj/item/reagent_containers/pill/charcoal(src)
new /obj/item/reagent_containers/pill/salicylic(src)
/obj/item/storage/pill_bottle/ert_gamma
wrapper_color = COLOR_YELLOW_GRAY
/obj/item/storage/pill_bottle/ert_gamma/populate_contents()
for(var/I in 1 to 6)
new /obj/item/reagent_containers/pill/pentetic(src)
new /obj/item/reagent_containers/pill/ironsaline(src)
new /obj/item/reagent_containers/pill/hydrocodone(src)
new /obj/item/reagent_containers/pill/mannitol(src)
new /obj/item/reagent_containers/pill/lazarus_reagent(src)
new /obj/item/reagent_containers/pill/rezadone(src)
/obj/item/storage/pill_bottle/MouseDrop(obj/over_object) // Best utilized if you're a cantankerous doctor with a Vicodin habit.
if(iscarbon(over_object))
var/mob/living/carbon/C = over_object
if(loc == C && src == C.get_active_hand())
if(!length(contents))
to_chat(C, "<span class='notice'>There is nothing in [src]!</span>")
return
C.visible_message("<span class='danger'>[C] [rapid_intake_message]</span>")
if(do_mob(C, C, 100)) // 10 seconds
for(var/obj/item/reagent_containers/pill/P in contents)
P.interact_with_atom(C, C)
C.visible_message("<span class='danger'>[C] [rapid_post_instake_message]</span>")
return
return ..()
/obj/item/storage/pill_bottle/attackby__legacy__attackchain(obj/item/I, mob/user, params)
if(is_pen(I))
rename_interactive(user, I)
else
return ..()
/obj/item/storage/pill_bottle/proc/apply_wrapper_color(color_number)
var/static/list/colors = list(COLOR_RED, COLOR_ORANGE, COLOR_YELLOW, COLOR_GREEN, COLOR_CYAN_BLUE, COLOR_VIOLET, COLOR_PURPLE)
wrapper_color = colors[(color_number - 1) % length(colors) + 1]
apply_wrap()
/obj/item/storage/pill_bottle/patch_pack
name = "patch pack"
desc = "It's a container for storing medical patches."
icon_state = "patch_pack"
belt_icon = "patch_pack"
use_sound = "patchpack"
can_hold = list(/obj/item/reagent_containers/patch)
cant_hold = list()
rapid_intake_message = "flips the lid of the patch pack open and begins rapidly stamping patches on themselves!"
rapid_post_instake_message = "stamps the entire contents of the patch pack all over their entire body!"
wrapper_state = "patch_pack_wrap"
/obj/item/storage/pill_bottle/charcoal
name = "Pill bottle (Charcoal)"
desc = "Contains pills used to counter toxins."
wrapper_color = COLOR_GREEN
/obj/item/storage/pill_bottle/charcoal/populate_contents()
for(var/I in 1 to 7)
new /obj/item/reagent_containers/pill/charcoal(src)
/obj/item/storage/pill_bottle/painkillers
name = "Pill Bottle (Salicylic Acid)"
desc = "Contains various pills for minor pain relief."
wrapper_color = COLOR_RED
/obj/item/storage/pill_bottle/painkillers/populate_contents()
for(var/I in 1 to 8)
new /obj/item/reagent_containers/pill/salicylic(src)
/obj/item/storage/pill_bottle/fakedeath
allow_wrap = FALSE
/obj/item/storage/pill_bottle/fakedeath/populate_contents()
new /obj/item/reagent_containers/pill/fakedeath(src)
new /obj/item/reagent_containers/pill/fakedeath(src)
new /obj/item/reagent_containers/pill/fakedeath(src)
/obj/item/storage/pill_bottle/patch_pack/ert
name = "ert red patch pack"
desc = "A patch pack containing medical patches. Issued to Nanotrasen ERT Red level medics."
wrapper_color = COLOR_NT_RED
/obj/item/storage/pill_bottle/patch_pack/ert/populate_contents()
for(var/I in 1 to 5)
new /obj/item/reagent_containers/patch/perfluorodecalin(src)
new /obj/item/reagent_containers/patch/silver_sulf(src)
new /obj/item/reagent_containers/patch/styptic(src)
/obj/item/storage/pill_bottle/patch_pack/ert/gamma
name = "ert gamma patch pack"
desc = "A patch pack containing medical patches. Issued to Nanotrasen ERT Gamma level medics."
wrapper_color = COLOR_YELLOW_GRAY
/obj/item/storage/pill_bottle/patch_pack/ert_amber
name = "ert amber patch pack"
desc = "A patch pack containing medical patches. Issued to Nanotrasen ERT Amber level medics"
wrapper_color = COLOR_ORANGE
/obj/item/storage/pill_bottle/patch_pack/ert_amber/populate_contents()
for(var/I in 1 to 5)
new /obj/item/reagent_containers/patch/silver_sulf/small(src)
new /obj/item/reagent_containers/patch/styptic/small(src)
@@ -1,394 +0,0 @@
/obj/item/storage/bag/garment
name = "garment bag"
desc = "A bag for storing extra clothes and shoes."
icon_state = "garment_bag"
slot_flags = NONE
w_class = WEIGHT_CLASS_BULKY
max_w_class = WEIGHT_CLASS_NORMAL
display_contents_with_number = FALSE
max_combined_w_class = 200
storage_slots = 27
resistance_flags = FLAMMABLE
can_hold = list(/obj/item/clothing)
cant_hold = list(
/obj/item/storage,
/obj/item/clothing/suit/space,
/obj/item/clothing/mask/cigarette,
/obj/item/clothing/mask/facehugger, //Why would you do this
/obj/item/clothing/accessory/medal,
/obj/item/clothing/suit/armor/riot,
/obj/item/clothing/suit/armor/reactive,
/obj/item/clothing/suit/armor/laserproof,
/obj/item/clothing/suit/hooded/ablative,
/obj/item/clothing/gloves/color/black/krav_maga,
)
/obj/item/storage/bag/garment/captain
name = "captain's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the captain."
/obj/item/storage/bag/garment/captain/populate_contents()
new /obj/item/clothing/head/caphat(src)
new /obj/item/clothing/head/caphat/parade(src)
new /obj/item/clothing/head/caphat/parade/white(src)
new /obj/item/clothing/head/beret/captain(src)
new /obj/item/clothing/head/beret/captain/white(src)
new /obj/item/clothing/head/crown/fancy(src)
new /obj/item/clothing/neck/cloak/captain(src)
new /obj/item/clothing/suit/armor/vest/capcarapace(src)
new /obj/item/clothing/suit/armor/vest/capcarapace/jacket(src)
new /obj/item/clothing/suit/armor/vest/capcarapace/jacket/tunic(src)
new /obj/item/clothing/suit/armor/vest/capcarapace/coat(src)
new /obj/item/clothing/suit/armor/vest/capcarapace/coat/white(src)
new /obj/item/clothing/neck/cloak/captain_mantle(src)
new /obj/item/clothing/under/rank/captain(src)
new /obj/item/clothing/under/rank/captain/skirt(src)
new /obj/item/clothing/under/rank/captain/white(src)
new /obj/item/clothing/under/rank/captain/skirt/white(src)
new /obj/item/clothing/under/rank/captain/parade(src)
new /obj/item/clothing/under/rank/captain/dress(src)
new /obj/item/clothing/gloves/color/captain(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/shoes/laceup(src)
new /obj/item/clothing/glasses/sunglasses(src)
new /obj/item/clothing/glasses/hud/security/sunglasses(src)
new /obj/item/clothing/glasses/hud/health/sunglasses(src)
new /obj/item/clothing/head/helmet/space/plasmaman/captain(src)
new /obj/item/clothing/under/plasmaman/captain(src)
/obj/item/storage/bag/garment/head_of_personnel
name = "head of personnel's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the head of personnel."
/obj/item/storage/bag/garment/head_of_personnel/populate_contents()
new /obj/item/clothing/head/hop(src)
new /obj/item/clothing/head/beret/hop(src)
new /obj/item/clothing/neck/cloak/head_of_personnel(src)
new /obj/item/clothing/neck/cloak/hop_mantle(src)
new /obj/item/clothing/suit/armor/vest(src)
new /obj/item/clothing/suit/hopcoat(src)
new /obj/item/clothing/under/rank/civilian/hop(src)
new /obj/item/clothing/under/rank/civilian/hop/skirt(src)
new /obj/item/clothing/under/rank/civilian/hop/dress(src)
new /obj/item/clothing/under/rank/civilian/hop/formal(src)
new /obj/item/clothing/under/rank/civilian/hop/oldman(src)
new /obj/item/clothing/under/suit/female(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/shoes/black(src)
new /obj/item/clothing/shoes/leather(src)
new /obj/item/clothing/shoes/white(src)
new /obj/item/clothing/glasses/sunglasses(src)
new /obj/item/clothing/glasses/hud/skills/sunglasses(src)
new /obj/item/clothing/head/helmet/space/plasmaman/hop(src)
new /obj/item/clothing/under/plasmaman/hop(src)
/obj/item/storage/bag/garment/head_of_security
name = "head of security's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the head of security."
/obj/item/storage/bag/garment/head_of_security/populate_contents()
new /obj/item/clothing/head/hos(src)
new /obj/item/clothing/head/beret/hos(src)
new /obj/item/clothing/neck/cloak/head_of_security(src)
new /obj/item/clothing/suit/armor/hos(src)
new /obj/item/clothing/suit/armor/hos/alt(src)
new /obj/item/clothing/neck/cloak/hos_mantle(src)
new /obj/item/clothing/under/rank/security/head_of_security(src)
new /obj/item/clothing/under/rank/security/formal/head_of_security(src)
new /obj/item/clothing/under/rank/security/head_of_security/corporate(src)
new /obj/item/clothing/under/rank/security/head_of_security/skirt(src)
new /obj/item/clothing/under/rank/security/head_of_security/skirt/corporate(src)
new /obj/item/clothing/glasses/hud/security/sunglasses(src)
new /obj/item/clothing/head/helmet/space/plasmaman/security/hos(src)
new /obj/item/clothing/under/plasmaman/security/hos(src)
/obj/item/storage/bag/garment/research_director
name = "research director's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the research director."
/obj/item/storage/bag/garment/research_director/populate_contents()
new /obj/item/clothing/head/rd (src)
new /obj/item/clothing/head/beret/rd(src)
new /obj/item/clothing/neck/cloak/research_director(src)
new /obj/item/clothing/under/rank/rnd/rd(src)
new /obj/item/clothing/under/rank/rnd/rd/skirt(src)
new /obj/item/clothing/suit/storage/labcoat/rd(src)
new /obj/item/clothing/neck/cloak/rd_mantle(src)
new /obj/item/clothing/suit/storage/labcoat(src)
new /obj/item/clothing/shoes/white(src)
new /obj/item/clothing/gloves/color/latex(src)
new /obj/item/clothing/glasses/science(src)
new /obj/item/clothing/glasses/welding/superior(src)
new /obj/item/clothing/glasses/hud/diagnostic/sunglasses(src)
new /obj/item/clothing/head/helmet/space/plasmaman/rd(src)
new /obj/item/clothing/under/plasmaman/rd(src)
/obj/item/storage/bag/garment/chief_medical_officer
name = "chief medical officer's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the chief medical officer."
/obj/item/storage/bag/garment/chief_medical_officer/populate_contents()
new /obj/item/clothing/head/cmo (src)
new /obj/item/clothing/head/beret/cmo (src)
new /obj/item/clothing/head/surgery/blue(src)
new /obj/item/clothing/head/surgery/green(src)
new /obj/item/clothing/head/surgery/purple(src)
new /obj/item/clothing/neck/cloak/chief_medical_officer(src)
new /obj/item/clothing/under/rank/medical/cmo(src)
new /obj/item/clothing/under/rank/medical/cmo/skirt(src)
new /obj/item/clothing/under/rank/medical/scrubs(src)
new /obj/item/clothing/under/rank/medical/scrubs/green(src)
new /obj/item/clothing/under/rank/medical/scrubs/purple(src)
new /obj/item/clothing/suit/storage/labcoat/cmo(src)
new /obj/item/clothing/neck/cloak/cmo_mantle(src)
new /obj/item/clothing/shoes/white(src)
new /obj/item/clothing/shoes/brown (src)
new /obj/item/clothing/gloves/color/latex/nitrile(src)
new /obj/item/clothing/head/helmet/space/plasmaman/cmo(src)
new /obj/item/clothing/under/plasmaman/cmo(src)
/obj/item/storage/bag/garment/chief_engineer
name = "chief engineer's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the chief engineer."
/obj/item/storage/bag/garment/chief_engineer/populate_contents()
new /obj/item/clothing/head/hardhat/white(src)
new /obj/item/clothing/head/beret/ce(src)
new /obj/item/clothing/head/beret/eng(src)
new /obj/item/clothing/neck/cloak/chief_engineer(src)
new /obj/item/clothing/under/rank/engineering/chief_engineer(src)
new /obj/item/clothing/under/rank/engineering/chief_engineer/skirt(src)
new /obj/item/clothing/neck/cloak/ce_mantle(src)
new /obj/item/clothing/suit/storage/hazardvest/ce(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/glasses/welding/superior(src)
new /obj/item/clothing/glasses/meson/sunglasses(src)
new /obj/item/clothing/gloves/color/yellow(src)
new /obj/item/clothing/head/helmet/space/plasmaman/engineering/ce(src)
new /obj/item/clothing/under/plasmaman/engineering/ce(src)
/obj/item/storage/bag/garment/nanotrasen_representative
name = "\improper Nanotrasen representative's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the Nanotrasen representative."
/obj/item/storage/bag/garment/nanotrasen_representative/populate_contents()
new /obj/item/clothing/head/ntrep(src)
new /obj/item/clothing/under/rank/procedure/representative(src)
new /obj/item/clothing/under/rank/procedure/representative/skirt(src)
new /obj/item/clothing/under/rank/procedure/representative/formal(src)
new /obj/item/clothing/under/suit/female(src)
new /obj/item/clothing/shoes/centcom(src)
new /obj/item/clothing/shoes/sandal/fancy(src)
new /obj/item/clothing/glasses/hud/skills/sunglasses(src)
new /obj/item/clothing/glasses/sunglasses(src)
new /obj/item/clothing/gloves/color/white(src)
new /obj/item/clothing/head/helmet/space/plasmaman/white(src)
new /obj/item/clothing/under/plasmaman/enviroslacks(src)
/obj/item/storage/bag/garment/magistrate
name = "magistrate's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the magistrate."
/obj/item/storage/bag/garment/magistrate/populate_contents()
new /obj/item/clothing/head/justice_wig(src)
new /obj/item/clothing/head/powdered_wig(src)
new /obj/item/clothing/under/rank/procedure/magistrate(src)
new /obj/item/clothing/under/rank/procedure/magistrate/skirt(src)
new /obj/item/clothing/under/rank/procedure/magistrate/formal(src)
new /obj/item/clothing/suit/magirobe(src)
new /obj/item/clothing/shoes/centcom(src)
new /obj/item/clothing/glasses/sunglasses(src)
new /obj/item/clothing/gloves/color/white(src)
new /obj/item/clothing/head/helmet/space/plasmaman/white(src)
new /obj/item/clothing/under/plasmaman/enviroslacks(src)
/obj/item/storage/bag/garment/blueshield
name = "blueshield's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the blueshield."
/obj/item/storage/bag/garment/blueshield/populate_contents()
new /obj/item/clothing/head/beret/centcom/officer(src)
new /obj/item/clothing/head/beret/centcom/officer/navy(src)
new /obj/item/clothing/under/rank/procedure/blueshield(src)
new /obj/item/clothing/under/rank/procedure/blueshield/skirt(src)
new /obj/item/clothing/under/rank/procedure/blueshield/formal(src)
new /obj/item/clothing/suit/armor/vest/blueshield(src)
new /obj/item/clothing/suit/storage/blueshield(src)
new /obj/item/clothing/shoes/centcom(src)
new /obj/item/clothing/shoes/jackboots/jacksandals(src)
new /obj/item/clothing/mask/gas/sechailer(src)
new /obj/item/clothing/glasses/sunglasses(src)
new /obj/item/clothing/glasses/hud/security/sunglasses(src)
new /obj/item/clothing/glasses/hud/health/sunglasses(src)
new /obj/item/clothing/glasses/hud/skills/sunglasses(src)
new /obj/item/clothing/neck/tie/blue(src)
new /obj/item/clothing/head/helmet/space/plasmaman/blueshield(src)
new /obj/item/clothing/under/plasmaman/blueshield(src)
/obj/item/storage/bag/garment/quartermaster
name = "quartermaster's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the quartermaster."
/obj/item/storage/bag/garment/quartermaster/populate_contents()
new /obj/item/clothing/under/rank/cargo/qm(src)
new /obj/item/clothing/under/rank/cargo/qm/skirt(src)
new /obj/item/clothing/under/rank/cargo/qm/dress(src)
new /obj/item/clothing/under/rank/cargo/qm/formal(src)
new /obj/item/clothing/under/rank/cargo/qm/whimsy(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/head/qm(src)
new /obj/item/clothing/head/beret/qm(src)
new /obj/item/clothing/neck/cloak/quartermaster(src)
new /obj/item/clothing/head/hardhat/orange(src)
new /obj/item/clothing/suit/qmcoat(src)
new /obj/item/clothing/neck/cloak/qm_mantle(src)
new /obj/item/clothing/suit/storage/hazardvest/qm(src)
new /obj/item/clothing/gloves/color/black(src)
new /obj/item/tank/internals/emergency_oxygen/double(src)
new /obj/item/clothing/head/helmet/space/plasmaman/cargo(src)
new /obj/item/clothing/under/plasmaman/cargo(src)
/obj/item/storage/bag/garment/warden
name = "warden's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the warden."
/obj/item/storage/bag/garment/warden/populate_contents()
new /obj/item/clothing/suit/armor/vest/warden(src)
new /obj/item/clothing/head/warden(src)
new /obj/item/clothing/suit/armor/vest/warden/alt(src)
new /obj/item/clothing/head/beret/warden(src)
new /obj/item/clothing/under/rank/security/warden(src)
new /obj/item/clothing/under/rank/security/formal/warden(src)
new /obj/item/clothing/under/rank/security/warden/corporate(src)
new /obj/item/clothing/under/rank/security/warden/skirt(src)
new /obj/item/clothing/under/rank/security/warden/skirt/corporate(src)
new /obj/item/clothing/mask/gas/sechailer/swat/warden(src)
new /obj/item/clothing/glasses/hud/security/sunglasses(src)
new /obj/item/clothing/head/helmet/space/plasmaman/security/warden(src)
new /obj/item/clothing/under/plasmaman/security/warden(src)
/obj/item/storage/bag/garment/detective
name = "detective's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the detective."
/obj/item/storage/bag/garment/detective/populate_contents()
new /obj/item/clothing/under/rank/security/detective(src)
new /obj/item/clothing/suit/storage/det_suit(src)
new /obj/item/clothing/suit/storage/det_suit/forensics/blue(src)
new /obj/item/clothing/suit/storage/det_suit/forensics/red(src)
new /obj/item/clothing/gloves/color/black/forensics(src)
new /obj/item/clothing/head/det_hat(src)
new /obj/item/clothing/shoes/brown(src)
new /obj/item/clothing/suit/armor/vest/det_suit(src)
new /obj/item/clothing/neck/tie/black(src)
new /obj/item/clothing/accessory/holster/armpit(src)
new /obj/item/clothing/glasses/sunglasses/yeah(src)
/obj/item/storage/bag/garment/chaplain
name = "chaplain's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the chaplain."
/obj/item/storage/bag/garment/chaplain/populate_contents()
new /obj/item/clothing/under/rank/civilian/chaplain(src)
new /obj/item/clothing/shoes/black(src)
new /obj/item/clothing/suit/hooded/abaya(src)
new /obj/item/clothing/suit/hooded/nun(src)
new /obj/item/clothing/suit/hooded/chaplain_hoodie(src)
new /obj/item/clothing/suit/hooded/monk(src)
new /obj/item/clothing/suit/witchhunter(src)
new /obj/item/clothing/head/witchhunter_hat(src)
new /obj/item/clothing/suit/holidaypriest(src)
new /obj/item/clothing/head/helmet/riot/knight/templar(src)
new /obj/item/clothing/suit/armor/riot/knight/templar(src)
new /obj/item/clothing/suit/storage/labcoat(src)
new /obj/item/clothing/head/helmet/space/plasmaman/chaplain(src)
new /obj/item/clothing/under/plasmaman/chaplain(src)
/obj/item/storage/bag/garment/psychologist
name = "psychologist's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the psychologist."
/obj/item/storage/bag/garment/psychologist/populate_contents()
new /obj/item/clothing/under/rank/medical/psych(src)
new /obj/item/clothing/under/rank/medical/psych/turtleneck(src)
new /obj/item/clothing/under/rank/medical/doctor(src)
new /obj/item/clothing/under/rank/medical/doctor/skirt(src)
new /obj/item/clothing/suit/storage/labcoat/psych(src)
new /obj/item/clothing/shoes/laceup(src)
new /obj/item/clothing/glasses/hud/health(src)
new /obj/item/clothing/glasses/hud/skills(src)
new /obj/item/clothing/neck/tie/blue(src)
new /obj/item/clothing/head/helmet/space/plasmaman(src)
new /obj/item/clothing/under/plasmaman(src)
/obj/item/storage/bag/garment/paramedic
name = "paramedic's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the paramedic."
/obj/item/storage/bag/garment/paramedic/populate_contents()
new /obj/item/clothing/under/rank/medical/paramedic(src)
new /obj/item/clothing/under/rank/medical/paramedic/skirt(src)
new /obj/item/clothing/head/soft/paramedic(src)
new /obj/item/clothing/head/beret/paramedic(src)
new /obj/item/clothing/suit/storage/labcoat/emt(src)
new /obj/item/clothing/suit/storage/hazardvest/paramedic(src)
new /obj/item/clothing/glasses/hud/health/sunglasses(src)
new /obj/item/clothing/gloves/color/latex(src)
new /obj/item/clothing/gloves/color/latex/nitrile(src)
new /obj/item/clothing/shoes/black(src)
new /obj/item/clothing/head/helmet/space/plasmaman/medical(src)
new /obj/item/clothing/under/plasmaman/medical(src)
/obj/item/storage/bag/garment/explorer
name = "explorer's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the explorer."
/obj/item/storage/bag/garment/explorer/populate_contents()
new /obj/item/clothing/under/rank/cargo/expedition(src)
new /obj/item/clothing/under/rank/cargo/expedition/overalls(src)
new /obj/item/clothing/head/soft/expedition(src)
new /obj/item/clothing/head/beret/expedition(src)
new /obj/item/clothing/gloves/color/black(src)
new /obj/item/clothing/shoes/jackboots(src)
new /obj/item/clothing/mask/gas/explorer(src)
/obj/item/storage/bag/garment/smith
name = "smith's garment bag"
desc = "A bag for storing extra clothes and shoes. This one belongs to the smith."
/obj/item/storage/bag/garment/smith/populate_contents()
new /obj/item/clothing/under/rank/cargo/smith(src)
new /obj/item/clothing/under/rank/cargo/smith/skirt(src)
new /obj/item/clothing/under/rank/cargo/smith/overalls(src)
new /obj/item/clothing/suit/apron/smith(src)
new /obj/item/clothing/suit/jacket/bomber/smith(src)
new /obj/item/clothing/head/soft/smith(src)
new /obj/item/clothing/head/beret/smith(src)
new /obj/item/clothing/gloves/smithing(src)
new /obj/item/clothing/shoes/workboots/smithing(src)
new /obj/item/clothing/under/plasmaman/smith(src)
new /obj/item/clothing/head/helmet/space/plasmaman/smith(src)
/obj/item/storage/bag/garment/syndie
name = "suspicious garment bag"
icon_state = "garment_bag_syndie"
desc = "A bag for storing extra clothes and shoes. Judging by the colors, this one belongs to someone with malicious intent."
/obj/item/storage/bag/garment/syndie/populate_contents()
new /obj/item/clothing/under/syndicate/tacticool(src)
new /obj/item/clothing/under/syndicate(src)
new /obj/item/clothing/under/syndicate/combat(src)
new /obj/item/clothing/under/syndicate/greyman(src)
new /obj/item/clothing/under/syndicate/sniper(src)
new /obj/item/clothing/mask/gas/syndicate(src)
new /obj/item/clothing/mask/balaclava(src)
new /obj/item/clothing/suit/storage/iaa/blackjacket(src)
new /obj/item/clothing/suit/blacktrenchcoat(src)
new /obj/item/clothing/head/beret/syndicate(src)
new /obj/item/clothing/glasses/syndie(src)
new /obj/item/clothing/neck/cloak/syndicate(src)
new /obj/item/clothing/gloves/color/black(src)
new /obj/item/clothing/gloves/fingerless(src)
new /obj/item/clothing/shoes/combat(src)
new /obj/item/clothing/shoes/laceup(src)
@@ -1,88 +0,0 @@
//A storage item intended to be used by other items to provide storage functionality.
//Types that use this should consider overriding emp_act() and hear_talk(), unless they shield their contents somehow.
/obj/item/storage/internal
var/obj/item/master_item
/obj/item/storage/internal/New(obj/item/MI)
master_item = MI
loc = master_item
name = master_item.name
..()
/obj/item/storage/internal/Destroy()
master_item = null
return ..()
/obj/item/storage/internal/attack_hand()
return //make sure this is never picked up
/obj/item/storage/internal/mob_can_equip(mob/M, slot, disable_warning = FALSE)
return 0 //make sure this is never picked up
//Helper procs to cleanly implement internal storages - storage items that provide inventory slots for other items.
//These procs are completely optional, it is up to the master item to decide when it's storage get's opened by calling open()
//However they are helpful for allowing the master item to pretend it is a storage item itself.
//If you are using these you will probably want to override attackby__legacy__attackchain() as well.
//See /obj/item/clothing/suit/storage for an example.
//items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour.
//returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of
//doing it without the ability to call another proc's parent, really.
/obj/item/storage/internal/proc/handle_mousedrop(mob/user as mob, obj/over_object as obj)
if(ishuman(user)) //so monkeys can take off their backpacks -- Urist
if(ismecha(user.loc)) // stops inventory actions in a mech
return 0
if(over_object == user && Adjacent(user)) // this must come before the screen objects only block
open(user)
return FALSE
if(!is_screen_atom(over_object))
return TRUE
//makes sure master_item is equipped before putting it in hand, so that we can't drag it into our hand from miles away.
//there's got to be a better way of doing this...
if(!(master_item.loc == user) || (master_item.loc && master_item.loc.loc == user))
return 0
if(!user.restrained() && !user.stat)
switch(over_object.name)
if("r_hand")
user.unequip(master_item)
user.put_in_r_hand(master_item)
if("l_hand")
user.unequip(master_item)
user.put_in_l_hand(master_item)
master_item.add_fingerprint(user)
return 0
return 0
//items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour.
//returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise.
//It's strange, but no other way of doing it without the ability to call another proc's parent, really.
/obj/item/storage/internal/proc/handle_attack_hand(mob/user as mob)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.l_store == master_item && !H.get_active_hand()) //Prevents opening if it's in a pocket.
H.put_in_hands(master_item)
H.l_store = null
return 0
if(H.r_store == master_item && !H.get_active_hand())
H.put_in_hands(master_item)
H.r_store = null
return 0
add_fingerprint(user)
if(master_item.loc == user)
open(user)
return 0
for(var/mob/M in range(1, master_item.loc))
if(M.s_active == src)
close(M)
return 1
/obj/item/storage/internal/Adjacent(atom/neighbor)
return master_item.Adjacent(neighbor)
@@ -1,796 +0,0 @@
// To clarify:
// For use_to_pickup and allow_quick_gather functionality,
// see item/attackby() (/game/objects/items.dm, params)
// Do not remove this functionality without good reason, cough reagent_containers cough.
// -Sayu
/obj/item/storage
name = "storage"
icon = 'icons/obj/storage.dmi'
flags_2 = BLOCKS_LIGHT_2
/// No message on putting items in.
var/silent = FALSE
/// List of objects which this item can store (if set, it can't store anything else)
var/list/can_hold = list()
/// List of objects that can be stored, regardless of w_class
var/list/w_class_override = list()
/// List of objects which this item can't store (in effect only if can_hold isn't set)
var/list/cant_hold = list()
/// List of objects which this item overrides the cant_hold list (used to negate cant_hold on specific items. Ex: Allowing Smuggler's Satchels (subtype of backpack) to be stored inside bags of holding.)
var/list/cant_hold_override = list()
/// Max size of objects that this object can store (in effect only if can_hold isn't set)
var/max_w_class = WEIGHT_CLASS_SMALL
/// The sum of the w_classes of all the items in this storage item.
var/max_combined_w_class = 14
/// The number of storage slots in this container.
var/storage_slots = 7
var/atom/movable/screen/storage/boxes = null
var/atom/movable/screen/close/closer = null
/// 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/use_to_pickup = FALSE
/// Set this to make the storage item group contents of the same type and display them as a number.
var/display_contents_with_number
/// Set this variable to allow the object to have the 'empty' verb, which dumps all the contents on the floor.
var/allow_quick_empty
/// Set this variable to allow the object to have the 'toggle mode' verb, which quickly collects all items from a tile.
var/allow_quick_gather
/// Pick up one item at a time or everything on the tile
var/pickup_all_on_tile = TRUE
/// Sound played when used. `null` for no sound.
var/use_sound = "rustle"
/// What kind of [/obj/item/stack] can this be folded into. (e.g. Boxes and cardboard)
var/foldable = null
/// How much of the stack item do you get.
var/foldable_amt = 0
/// Lazy list of mobs which are currently viewing the storage inventory.
var/list/mobs_viewing
// Allow storage items of the same size to be put inside
var/allow_same_size = FALSE
/obj/item/storage/Initialize(mapload)
. = ..()
can_hold = typecacheof(can_hold)
cant_hold = typecacheof(cant_hold) - typecacheof(cant_hold_override)
populate_contents()
boxes = new /atom/movable/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 /atom/movable/screen/close()
closer.master = src
closer.icon_state = "backpack_close"
closer.layer = ABOVE_HUD_LAYER
closer.plane = ABOVE_HUD_PLANE
orient2hud()
ADD_TRAIT(src, TRAIT_ADJACENCY_TRANSPARENT, ROUNDSTART_TRAIT)
RegisterSignal(src, COMSIG_ATOM_EXITED, PROC_REF(on_atom_exited))
/obj/item/storage/Destroy()
for(var/obj/O in contents)
O.mouse_opacity = initial(O.mouse_opacity)
QDEL_NULL(boxes)
QDEL_NULL(closer)
LAZYCLEARLIST(mobs_viewing)
return ..()
/obj/item/storage/examine(mob/user)
. = ..()
if(allow_quick_empty)
. += "<span class='notice'>You can use [src] in hand to empty it's entire contents.</span>"
if(allow_quick_gather)
. += "<span class='notice'>You can <b>Alt-Shift-Click</b> [src] to switch it's gathering method.</span>"
/obj/item/storage/forceMove(atom/destination)
. = ..()
if(!ismob(destination.loc))
for(var/mob/player in mobs_viewing)
if(player == destination)
continue
hide_from(player)
/obj/item/storage/proc/removal_allowed_check(mob/user)
return TRUE
/obj/item/storage/proc/dump_storage(mob/user, obj/item/storage/target)
if(!length(contents) || user.restrained() || (HAS_TRAIT(user, TRAIT_HANDS_BLOCKED)) || !user.can_reach(target) || src == target)
return
for(var/obj/item/thing in contents)
if(!target.can_be_inserted(thing))
continue
if(!do_after(user, 0.3 SECONDS, target = user))
break
playsound(loc, "rustle", 50, TRUE, -5)
target.handle_item_insertion(thing, user)
/obj/item/storage/MouseDrop(obj/over_object, src_location, over_location, src_control, over_control, params)
if(!ismob(usr)) //so monkeys can take off their backpacks -- Urist
return
var/mob/M = usr
if(ismecha(M.loc) || M.incapacitated(FALSE, TRUE)) // Stops inventory actions in a mech as well as while being incapacitated
return
if(over_object == M && Adjacent(M)) // this must come before the screen objects only block
if(M.s_active)
M.s_active.close(M)
open(M)
return
if(isstorage(over_object))
var/obj/item/storage = over_object
if(!storage.in_storage)
dump_storage(M, over_object)
return
else if(ismodcontrol(over_object))
var/obj/item/mod/control/mod = over_object
dump_storage(M, mod.bag)
return
if((istype(over_object, /obj/structure/table) || isfloorturf(over_object)) && length(contents) \
&& loc == M && !M.stat && !M.restrained() && !HAS_TRAIT(M, TRAIT_HANDS_BLOCKED) && over_object.Adjacent(M) && !istype(src, /obj/item/storage/lockbox)) // Worlds longest `if()`
var/turf/T = get_turf(over_object)
if(!removal_allowed_check(M))
return
if(isfloorturf(over_object))
if(get_turf(M) != T)
return // Can only empty containers onto the floor under you
if(tgui_alert(M, "Empty [src] onto [T]?", "Confirm", list("Yes", "No")) != "Yes")
return
if(!(M && over_object && length(contents) && loc == M && !M.stat && !M.restrained() && !HAS_TRAIT(M, TRAIT_HANDS_BLOCKED) && get_turf(M) == T))
return // Something happened while the player was thinking
hide_from(M)
M.face_atom(over_object)
M.visible_message("<span class='notice'>[M] empties [src] onto [over_object].</span>",
"<span class='notice'>You empty [src] onto [over_object].</span>")
var/list/params_list = params2list(params)
var/x_offset = text2num(params_list["icon-x"]) - 16
var/y_offset = text2num(params_list["icon-y"]) - 16
for(var/obj/item/I in contents)
remove_from_storage(I, T)
I.scatter_atom(x_offset, y_offset)
update_icon() // For content-sensitive icons
return
if(!is_screen_atom(over_object))
return ..()
if(!(loc == M) || (loc && loc.loc == M))
return
if(!M.restrained() && !M.stat)
switch(over_object.name)
if("r_hand")
if(!M.unequip(src))
return
M.put_in_r_hand(src)
if("l_hand")
if(!M.unequip(src))
return
M.put_in_l_hand(src)
add_fingerprint(usr)
return
if(over_object == usr && in_range(src, usr) || usr.contents.Find(src))
if(usr.s_active)
usr.s_active.close(usr)
open(usr)
/obj/item/storage/AltClick(mob/user)
if(ishuman(user) && Adjacent(user) && !user.incapacitated(FALSE, TRUE))
open(user)
add_fingerprint(user)
else if(isobserver(user))
show_to(user)
/**
* Loops through any nested containers inside `src`, and returns a list of everything inside them.
*
* Currently checks for storage containers, gifts containing storage containers, and folders.
*/
/obj/item/storage/proc/return_inv()
var/list/L = list()
L += contents // Inventory of the main storage item
for(var/obj/item/storage/S in src) // Inventory of nested storage items
L += S.return_inv()
for(var/obj/item/gift/G in src)
L += G.gift
if(isstorage(G.gift)) // If the gift contains a storage item
var/obj/item/storage/S = G.gift
L += S.return_inv()
for(var/obj/item/folder/F in src)
L += F.contents
return L
/**
* Shows `user` the contents of `src`, and activates any mouse trap style triggers.
*/
/obj/item/storage/proc/show_to(mob/user)
if(!user.client)
return
if(user.s_active != src && !isobserver(user))
for(var/obj/item/I in src)
if(I.on_found(user)) // For mouse traps and such
return // If something triggered, don't open the UI
orient2hud(user) // this only needs to happen to make .contents show properly as screen objects.
if(user.s_active)
user.s_active.hide_from(user) // If there's already an interface open, close it.
user.client.screen |= boxes
user.client.screen |= closer
user.client.screen |= contents
user.s_active = src
LAZYDISTINCTADD(mobs_viewing, user)
/**
* Hides the current container interface from `user`.
*/
/obj/item/storage/proc/hide_from(mob/user)
LAZYREMOVE(mobs_viewing, user) // Remove clientless mobs too
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
/**
* Hides the current container interface from all viewers.
*/
/obj/item/storage/proc/hide_from_all()
for(var/mob/M in mobs_viewing)
hide_from(M)
/**
* Checks all mobs currently viewing the storage inventory, and hides it if they shouldn't be able to see it.
*/
/obj/item/storage/proc/update_viewers()
for(var/_M in mobs_viewing)
var/mob/M = _M
if(!QDELETED(M) && M.s_active == src && Adjacent(M))
continue
hide_from(M)
for(var/obj/item/storage/child in src)
child.update_viewers()
/obj/item/storage/Moved(atom/oldloc, dir, forced = FALSE)
. = ..()
update_viewers()
/obj/item/storage/proc/open(mob/user)
if(isobserver(user))
show_to(user)
return
if(use_sound && isliving(user))
playsound(loc, use_sound, 50, TRUE, -5)
if(user.s_active)
user.s_active.close(user)
show_to(user)
/obj/item/storage/proc/close(mob/user)
hide_from(user)
user.s_active = null
/**
* Draws the inventory and places the items on it using custom positions.
*
* `tx` and `ty` are the upper left tile.
* `mx` and `my` are the bottom right tile.
*
* The numbers are calculated from the bottom left, with the bottom left 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)
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/datum/numbered_display/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 = "<font color='white' face='Small Fonts'>[(ND.number > 1) ? "[ND.number]" : ""]</font>"
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)
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)
return
sample_object = sample
number = 1
//This proc determins 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 = length(contents)
//Numbered contents display
var/list/datum/numbered_display/numbered_contents
if(display_contents_with_number)
for(var/obj/O in contents)
O.layer = initial(O.layer)
O.plane = initial(O.plane)
numbered_contents = list()
adjusted_contents = 0
for(var/obj/item/I in contents)
var/found = FALSE
for(var/datum/numbered_display/ND in numbered_contents)
if(ND.sample_object.should_stack_with(I))
ND.number++
found = TRUE
break
if(!found)
adjusted_contents++
numbered_contents += 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)
/**
* Checks whether `I` can be inserted into the container.
*
* Returns `TRUE` if it can, and `FALSE` if it can't.
* Arguments:
* * obj/item/I - The item to insert
* * stop_messages - Don't display a warning message if the item can't be inserted
*/
/obj/item/storage/proc/can_be_inserted(obj/item/I, stop_messages = FALSE)
if(!istype(I) || (I.flags & ABSTRACT)) // Not an item
return
if(loc == I)
return FALSE //Means the item is already in the storage item
if(!I.can_enter_storage(src, usr))
return FALSE
if(length(contents) >= storage_slots)
if(!stop_messages)
to_chat(usr, "<span class='warning'>[I] won't fit in [src], make some space!</span>")
return FALSE //Storage item is full
if(length(can_hold))
if(!is_type_in_typecache(I, can_hold))
if(!stop_messages)
to_chat(usr, "<span class='warning'>[src] cannot hold [I].</span>")
return FALSE
if(is_type_in_typecache(I, cant_hold)) //Check for specific items which this container can't hold.
if(!stop_messages)
to_chat(usr, "<span class='warning'>[src] cannot hold [I].</span>")
return FALSE
if(length(cant_hold) && isstorage(I)) //Checks nested storage contents for restricted objects, we don't want people sneaking the NAD in via boxes now, do we?
var/obj/item/storage/S = I
for(var/obj/A in S.return_inv())
if(is_type_in_typecache(A, cant_hold))
if(!stop_messages)
to_chat(usr, "<span class='warning'>[src] rejects [I] because of its contents.</span>")
return FALSE
if(I.w_class > max_w_class)
if(length(w_class_override))
if(is_type_in_list(I, w_class_override))
return TRUE
else
if(!stop_messages)
to_chat(usr, "<span class='warning'>[I] is too big for [src].</span>")
return FALSE
else
if(!stop_messages)
to_chat(usr, "<span class='warning'>[I] is too big for [src].</span>")
return FALSE
var/sum_w_class = I.w_class
for(var/obj/item/item in contents)
sum_w_class += item.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, "<span class='warning'>[src] is full, make some space.</span>")
return FALSE
if(I.w_class >= w_class && isstorage(I))
if(!allow_same_size) //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, "<span class='warning'>[src] cannot hold [I] as it's a storage item of the same size.</span>")
return FALSE //To prevent the stacking of same sized storage items.
if(I.flags & NODROP) //SHOULD be handled in unEquip, but better safe than sorry.
to_chat(usr, "<span class='warning'>[I] is stuck to your hand, you can't put it in [src]</span>")
return FALSE
return TRUE
/**
* Handles items being inserted into a storage container.
*
* This doesn't perform any checks of whether an item can be inserted. That's done by [/obj/item/storage/proc/can_be_inserted]
* Arguments:
* * obj/item/I - The item to be inserted
* * mob/user - The mob performing the insertion
* * prevent_warning - Stop the insertion message being displayed. Intended for cases when you are inserting multiple items at once.
*/
/obj/item/storage/proc/handle_item_insertion(obj/item/I, mob/user, prevent_warning = FALSE)
if(!istype(I))
return FALSE
if(user)
if(!Adjacent(user) && !isnewplayer(user))
return FALSE
if(!user.unequip(I))
return FALSE
user.update_icons() //update our overlays
if(QDELING(I))
return FALSE
if(silent || HAS_TRAIT(I, TRAIT_SILENT_INSERTION))
prevent_warning = TRUE
I.forceMove(src)
if(QDELING(I))
return FALSE
I.on_enter_storage(src)
for(var/_M in mobs_viewing)
var/mob/M = _M
if((M.s_active == src) && M.client)
M.client.screen += I
if(user)
if(user.client && user.s_active != src)
user.client.screen -= I
if(length(user.observers))
for(var/mob/observer in user.observers)
if(observer.client && observer.s_active != src)
observer.client.screen -= I
I.dropped(user, TRUE)
if(user)
add_fingerprint(user)
if(!prevent_warning)
// the item's user will always get a notification
to_chat(user, "<span class='notice'>You put [I] into [src].</span>")
// if the item less than normal sized, only people within 1 tile get the message, otherwise, everybody in view gets it
if(I.w_class < WEIGHT_CLASS_NORMAL)
for(var/mob/M in orange(1, user))
if(in_range(M, user))
M.show_message("<span class='notice'>[user] puts [I] into [src].</span>")
else
// restrict player list to include only those in view
for(var/mob/M in oviewers(7, user))
M.show_message("<span class='notice'>[user] puts [I] into [src].</span>")
orient2hud(user)
if(user)
if(user.s_active)
user.s_active.show_to(user)
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
I.in_inventory = TRUE
update_icon()
return TRUE
/obj/item/storage/proc/on_atom_exited(datum/source, atom/exited, direction)
return remove_from_storage(exited, exited.loc)
/**
* Handles the removal of an item from a storage container.
*
* Arguments:
* * obj/item/I - The item to be removed
* * atom/new_location - The location to send the item to.
*/
/obj/item/storage/proc/remove_from_storage(obj/item/I, atom/new_location)
if(!istype(I))
return FALSE
for(var/_M in mobs_viewing)
var/mob/M = _M
if((M.s_active == src) && M.client)
M.client.screen -= I
if(new_location)
if(ismob(loc))
I.dropped(usr, TRUE)
if(ismob(new_location))
I.layer = ABOVE_HUD_LAYER
I.plane = ABOVE_HUD_PLANE
else
I.layer = initial(I.layer)
I.plane = initial(I.plane)
I.forceMove(new_location)
else
I.forceMove(get_turf(src))
if(usr)
orient2hud(usr)
if(usr.s_active)
usr.s_active.show_to(usr)
if(I.maptext)
I.maptext = ""
I.on_exit_storage(src)
I.mouse_opacity = initial(I.mouse_opacity)
update_icon()
return TRUE
/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__legacy__attackchain(obj/item/I, mob/user, params)
..()
if(istype(I, /obj/item/hand_labeler))
var/obj/item/hand_labeler/labeler = I
if(labeler.mode)
return FALSE
if(user.a_intent != INTENT_HELP && issimulatedturf(loc)) // Stops you from putting your baton in the storage on accident
return FALSE
. = TRUE //no afterattack
if(isrobot(user))
return //Robots can't interact with storage items.
if(!can_be_inserted(I))
if(length(contents) >= storage_slots) //don't use items on the backpack if they don't fit
return TRUE
return FALSE
handle_item_insertion(I, user)
/obj/item/storage/attack_hand(mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(!H.get_active_hand())
if(H.l_store == src) //Prevents opening if it's in a pocket.
H.put_in_hands(src)
H.l_store = null
return
if(H.r_store == src)
H.put_in_hands(src)
H.r_store = null
return
orient2hud(user)
if(loc == user)
if(user.s_active)
user.s_active.close(user)
open(user)
else
..()
add_fingerprint(user)
/obj/item/storage/equipped(mob/user, slot, initial)
. = ..()
update_viewers()
/obj/item/storage/attack_ghost(mob/user)
if(isobserver(user))
// Revenants don't get to play with the toys.
show_to(user)
return ..()
/obj/item/storage/AltShiftClick(mob/living/carbon/human/user)
pickup_all_on_tile = !pickup_all_on_tile
switch(pickup_all_on_tile)
if(TRUE)
to_chat(usr, "[src] now picks up all items in a tile at once.")
if(FALSE)
to_chat(usr, "[src] now picks up one item at a time.")
/obj/item/storage/proc/drop_inventory(user)
var/turf/T = get_turf(src)
hide_from(user)
for(var/obj/item/I in contents)
remove_from_storage(I, T)
I.scatter_atom()
CHECK_TICK
/**
* Populates the container with items
*
* Override with whatever you want to put in the container
*/
/obj/item/storage/proc/populate_contents()
return // Override
/obj/item/storage/emp_act(severity)
..()
for(var/I in contents)
var/atom/A = I
A.emp_act(severity)
/obj/item/storage/hear_talk(mob/living/M, list/message_pieces)
..()
for(var/obj/O in contents)
O.hear_talk(M, message_pieces)
/obj/item/storage/hear_message(mob/living/M, msg)
..()
for(var/obj/O in contents)
O.hear_message(M, msg)
/obj/item/storage/attack_self__legacy__attackchain(mob/user)
//Clicking on itself will empty it, if allow_quick_empty is TRUE
if(allow_quick_empty && user.is_in_active_hand(src))
drop_inventory(user)
else if(foldable)
fold(user)
/obj/item/storage/proc/fold(mob/user)
if(length(contents))
to_chat(user, "<span class='warning'>You can't fold this [name] with items still inside!</span>")
return
if(!ispath(foldable))
return
var/found = FALSE
for(var/mob/M in range(1))
if(M.s_active == src) // Close any open UI windows first
close(M)
if(M == user)
found = TRUE
if(!found) // User is too far away
return
to_chat(user, "<span class='notice'>You fold [src] flat.</span>")
var/obj/item/stack/I = new foldable(get_turf(src), foldable_amt)
user.put_in_hands(I)
qdel(src)
/**
* Returns the storage depth of an atom up to the area level.
*
* The storage depth is the number of storage items the atom is contained in.
* Returns `-1` if the atom was not found in a container.
*/
/atom/proc/storage_depth(atom/container)
var/depth = 0
var/atom/cur_atom = src
while(cur_atom && !(cur_atom in container.contents))
if(isarea(cur_atom))
return -1
if(isstorage(cur_atom.loc))
depth++
cur_atom = cur_atom.loc
if(!cur_atom)
return -1 //inside something with a null loc.
return depth
/**
* Like [/atom/proc/storage_depth], but returns the depth to the nearest turf.
*
* Returns `-1` if there's no top level turf. (A loc was null somewhere, or a non-turf atom's loc was an area somehow.)
*/
/atom/proc/storage_depth_turf()
var/depth = 0
var/atom/cur_atom = src
while(cur_atom && !isturf(cur_atom))
if(isarea(cur_atom))
return -1
if(isstorage(cur_atom.loc))
depth++
cur_atom = cur_atom.loc
if(!cur_atom)
return -1 //inside something with a null loc.
return depth
/obj/item/storage/serialize()
var/data = ..()
var/list/content_list = list()
data["content"] = content_list
data["slots"] = storage_slots
data["max_w_class"] = max_w_class
data["max_c_w_class"] = max_combined_w_class
for(var/thing in contents)
var/atom/movable/AM = thing
// This code does not watch out for infinite loops
// But then again a tesseract would destroy the server anyways
// Also I wish I could just insert a list instead of it reading it the wrong way
content_list.len++
content_list[length(content_list)] = AM.serialize()
return data
/obj/item/storage/deserialize(list/data)
if(isnum(data["slots"]))
storage_slots = data["slots"]
if(isnum(data["max_w_class"]))
max_w_class = data["max_w_class"]
if(isnum(data["max_c_w_class"]))
max_combined_w_class = data["max_c_w_class"]
for(var/thing in contents)
qdel(thing) // out with the old
for(var/thing in data["content"])
if(islist(thing))
list_to_object(thing, src)
else if(thing == null)
stack_trace("Null entry found in storage/deserialize.")
else
stack_trace("Non-list thing found in storage/deserialize (Thing: [thing])")
..()
/obj/item/storage/AllowDrop()
return TRUE
/obj/item/storage/ex_act(severity)
for(var/atom/A in contents)
A.ex_act(severity)
CHECK_TICK
..()
/obj/item/storage/proc/can_items_stack(obj/item/item_1, obj/item/item_2)
if(!item_1 || !item_2)
return
return item_1.type == item_2.type && item_1.name == item_2.name
/obj/item/storage/proc/swap_items(obj/item/item_1, obj/item/item_2, mob/user = null)
if(!(item_1.loc == src && item_2.loc == src))
return
var/index_1 = contents.Find(item_1)
var/index_2 = contents.Find(item_2)
var/list/new_contents = contents.Copy()
new_contents.Swap(index_1, index_2)
contents = new_contents
if(user && user.s_active == src)
orient2hud(user)
show_to(user)
@@ -1,45 +0,0 @@
// Sprites from CM13
/obj/item/storage/surgical_tray
name = "surgical tray"
desc = "A small metallic tray covered in sterile tarp. Intended to store surgical tools in a neat and clean fashion."
icon_state = "surgical_tray"
storage_slots = 22 // 11 Items, x2 to be sure
w_class = WEIGHT_CLASS_BULKY
max_w_class = WEIGHT_CLASS_GIGANTIC
max_combined_w_class = 38 // Items listed add up to 19, x2 to be sure
can_hold = list(
/obj/item/scalpel,
/obj/item/cautery,
/obj/item/hemostat,
/obj/item/retractor,
/obj/item/fix_o_vein,
/obj/item/surgicaldrill,
/obj/item/circular_saw,
/obj/item/bonegel,
/obj/item/bonesetter,
/obj/item/stack/medical/bruise_pack,
/obj/item/stack/medical/ointment,
/obj/item/surgical_drapes,
/obj/item/dissector,
)
/obj/item/storage/surgical_tray/Initialize(mapload)
. = ..()
new /obj/item/scalpel(src)
new /obj/item/cautery(src)
new /obj/item/hemostat(src)
new /obj/item/retractor(src)
new /obj/item/fix_o_vein(src)
new /obj/item/surgicaldrill(src)
new /obj/item/circular_saw(src)
new /obj/item/bonegel(src)
new /obj/item/bonesetter(src)
new /obj/item/stack/medical/bruise_pack/advanced(src)
new /obj/item/stack/medical/ointment/advanced(src)
new /obj/item/surgical_drapes(src)
/obj/item/storage/surgical_tray/update_icon_state()
if(!length(contents))
icon_state = "surgical_tray_e"
else
icon_state = "surgical_tray"
@@ -1,126 +0,0 @@
/obj/item/storage/wallet
name = "leather wallet"
desc = "Made from genuine leather, it is of the highest quality."
storage_slots = 10
icon = 'icons/obj/wallets.dmi'
icon_state = "wallet"
w_class = WEIGHT_CLASS_SMALL
resistance_flags = FLAMMABLE
can_hold = list(
/obj/item/stack/spacecash,
/obj/item/card,
/obj/item/clothing/mask/cigarette,
/obj/item/flashlight/pen,
/obj/item/seeds,
/obj/item/stack/medical,
/obj/item/toy/crayon,
/obj/item/coin,
/obj/item/food/candy/chocolate_coin,
/obj/item/food/candy/coin,
/obj/item/food/candy/cash,
/obj/item/food/customizable/candy/coin,
/obj/item/food/customizable/candy/cash,
/obj/item/dice,
/obj/item/disk,
/obj/item/bio_chip_implanter,
/obj/item/lighter,
/obj/item/match,
/obj/item/paper,
/obj/item/pen,
/obj/item/photo,
/obj/item/reagent_containers/dropper,
/obj/item/screwdriver,
/obj/item/stamp)
cant_hold = list(
/obj/item/screwdriver/power
)
slot_flags = ITEM_SLOT_ID
var/obj/item/card/id/front_id = null
// allows for clicking of stuff on our person/on the ground to put in the wallet, so easy to stick your ID in your wallet
use_to_pickup = TRUE
pickup_all_on_tile = FALSE
/obj/item/storage/wallet/remove_from_storage(obj/item/I, atom/new_location)
. = ..()
if(. && istype(I, /obj/item/card/id))
refresh_ID()
/obj/item/storage/wallet/handle_item_insertion(obj/item/I, mob/user, prevent_warning = FALSE)
. = ..()
if(. && istype(I, /obj/item/card/id))
refresh_ID()
/obj/item/storage/wallet/orient2hud(mob/user)
. = ..()
refresh_ID()
/obj/item/storage/wallet/proc/refresh_ID()
// Locate the first ID in the wallet
front_id = (locate(/obj/item/card/id) in contents)
if(ishuman(loc))
var/mob/living/carbon/human/wearing_human = loc
if(wearing_human.wear_id == src)
wearing_human.sec_hud_set_ID()
update_appearance(UPDATE_NAME|UPDATE_OVERLAYS)
/obj/item/storage/wallet/update_overlays()
. = ..()
if(!front_id)
return
. += mutable_appearance(front_id.icon, front_id.icon_state)
. += front_id.overlays
. += mutable_appearance(icon, "wallet_overlay")
// fuck yeah, ass photo in my wallet
var/obj/item/photo/photo = locate(/obj/item/photo) in contents
if(!photo)
return
var/mutable_appearance/MA = mutable_appearance(photo.appearance)
MA.pixel_x = 11
MA.pixel_y = 1
. += MA
. += mutable_appearance(icon, "photo_overlay")
/obj/item/storage/wallet/update_name(updates)
. = ..()
if(front_id)
name = "wallet displaying [front_id]"
else
name = initial(name)
/obj/item/storage/wallet/GetID()
return front_id
/obj/item/storage/wallet/GetAccess()
var/obj/item/I = GetID()
if(I)
return I.GetAccess()
else
return ..()
/obj/item/storage/wallet/random/populate_contents()
var/cash = pick(/obj/item/stack/spacecash,
/obj/item/stack/spacecash/c5,
/obj/item/stack/spacecash/c10,
/obj/item/stack/spacecash/c50,
/obj/item/stack/spacecash/c100)
var/coin = pickweight(list(/obj/item/coin/iron = 3,
/obj/item/coin/silver = 2,
/obj/item/coin/gold = 1))
new cash(src)
if(prob(50)) // 50% chance of a second
new cash(src)
new coin(src)
// Arcade Wallet
/obj/item/storage/wallet/cheap
name = "cheap wallet"
desc = "A cheap and flimsy wallet from the arcade."
storage_slots = 5 //smaller storage than normal wallets
@@ -1,243 +0,0 @@
/obj/item/tank/jetpack
name = "Jetpack (Empty)"
desc = "A tank of compressed gas for use as propulsion in zero-gravity areas. Use with caution."
icon_state = "jetpack"
w_class = WEIGHT_CLASS_BULKY
item_state = "jetpack"
lefthand_file = 'icons/mob/inhands/jetpack_lefthand.dmi'
righthand_file = 'icons/mob/inhands/jetpack_righthand.dmi'
distribute_pressure = ONE_ATMOSPHERE * O2STANDARD
actions_types = list(/datum/action/item_action/set_internals, /datum/action/item_action/toggle_jetpack, /datum/action/item_action/jetpack_stabilization)
var/gas_type = "oxygen"
var/on = FALSE
var/volume_rate = 500 //Needed for borg jetpack transfer
var/stabilize = FALSE
var/thrust_callback
/obj/item/tank/jetpack/Initialize(mapload)
. = ..()
thrust_callback = CALLBACK(src, PROC_REF(allow_thrust), 0.01)
configure_jetpack(stabilize)
/obj/item/tank/jetpack/Destroy()
thrust_callback = null
return ..()
/**
* configures/re-configures the jetpack component
*
* Arguments
* stabilize - Should this jetpack be stabalized
*/
/obj/item/tank/jetpack/proc/configure_jetpack(stabilize)
src.stabilize = stabilize
AddComponent( \
/datum/component/jetpack, \
src.stabilize, \
COMSIG_JETPACK_ACTIVATED, \
COMSIG_JETPACK_DEACTIVATED, \
JETPACK_ACTIVATION_FAILED, \
thrust_callback, \
/datum/effect_system/trail_follow/ion \
)
/obj/item/tank/jetpack/populate_gas()
if(gas_type)
switch(gas_type)
if("oxygen")
air_contents.set_oxygen(((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)))
if("carbon dioxide")
air_contents.set_carbon_dioxide(((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C)))
/obj/item/tank/jetpack/on_mob_move(direction, mob/user)
if(on)
var/turf/T = get_step(src, REVERSE_DIR(direction))
if(!has_gravity(T))
new /obj/effect/particle_effect/ion_trails(T, direction)
/obj/item/tank/jetpack/ui_action_click(mob/user, actiontype)
if(actiontype == /datum/action/item_action/toggle_jetpack)
cycle(user)
else if(actiontype == /datum/action/item_action/jetpack_stabilization)
toggle_stabilization(user)
else
toggle_internals(user)
/obj/item/tank/jetpack/proc/toggle_stabilization(mob/user)
if(on)
configure_jetpack(!stabilize)
to_chat(user, "<span class='notice'>You turn [src]'s stabilization [stabilize ? "on" : "off"].</span>")
/obj/item/tank/jetpack/proc/cycle(mob/user)
if(user.incapacitated())
return
if(!on)
turn_on(user)
to_chat(user, "<span class='notice'>You turn the jetpack on.</span>")
else
turn_off(user)
to_chat(user, "<span class='notice'>You turn the jetpack off.</span>")
update_action_buttons()
/obj/item/tank/jetpack/proc/turn_on(mob/user)
if(SEND_SIGNAL(src, COMSIG_JETPACK_ACTIVATED, user) & JETPACK_ACTIVATION_FAILED)
return FALSE
on = TRUE
icon_state = "[initial(icon_state)]-on"
/obj/item/tank/jetpack/proc/turn_off(mob/user)
SEND_SIGNAL(src, COMSIG_JETPACK_DEACTIVATED, user)
on = FALSE
icon_state = initial(icon_state)
/obj/item/tank/jetpack/dropped(mob/user, silent)
. = ..()
if(on)
turn_off(user)
/obj/item/tank/jetpack/proc/allow_thrust(num)
if(!ismob(loc))
return FALSE
var/mob/user = loc
if((num < 0.005 || air_contents.total_moles() < num))
turn_off(user)
return FALSE
var/datum/gas_mixture/removed = air_contents.remove(num)
if(removed.total_moles() < 0.005)
turn_off(user)
return FALSE
var/turf/T = get_turf(user)
T.blind_release_air(removed)
return TRUE
/obj/item/tank/jetpack/improvised
name = "improvised jetpack"
desc = "A jetpack made from two air tanks, a fire extinguisher and some atmospherics equipment. It doesn't look like it can hold much."
icon_state = "jetpack-improvised"
item_state = "jetpack-improvised"
volume = 20 //normal jetpacks have 70 volume
gas_type = null //it starts empty
/obj/item/tank/jetpack/improvised/allow_thrust(num, mob/living/user)
if(rand(0, 250) == 0)
to_chat(user, "<span class='notice'>You feel your jetpack's engines cut out.</span>")
turn_off(user)
return
return ..()
/obj/item/tank/jetpack/void
name = "Void Jetpack (Oxygen)"
desc = "It works well in a void."
icon_state = "jetpack-void"
item_state = "jetpack-void"
/obj/item/tank/jetpack/void/grey
icon_state = "jetpack-void-grey"
item_state = "jetpack-void-grey"
/obj/item/tank/jetpack/void/gold
name = "Retro Jetpack (Oxygen)"
icon_state = "jetpack-void-gold"
item_state = "jetpack-void-gold"
/obj/item/tank/jetpack/oxygen
name = "Jetpack (Oxygen)"
desc = "A tank of compressed oxygen for use as propulsion in zero-gravity areas. Use with caution."
/obj/item/tank/jetpack/oxygen/harness
name = "jet harness (oxygen)"
desc = "A lightweight tactical harness, used by those who don't want to be weighed down by traditional jetpacks."
icon_state = "jetpack-mini"
item_state = "jetpack-mini"
volume = 40
throw_range = 7
w_class = WEIGHT_CLASS_NORMAL
/obj/item/tank/jetpack/oxygen/captain
name = "Captain's jetpack"
desc = "A compact, lightweight jetpack containing a high amount of compressed oxygen."
icon_state = "jetpack-captain"
item_state = "jetpack-captain"
volume = 90
w_class = WEIGHT_CLASS_NORMAL
/obj/item/tank/jetpack/oxygen/security
name = "security jetpack (oxygen)"
desc = "A tank of compressed oxygen for use as propulsion in zero-gravity areas by security forces."
icon_state = "jetpack-sec"
item_state = "jetpack-sec"
/obj/item/tank/jetpack/carbondioxide
name = "Jetpack (Carbon Dioxide)"
desc = "A tank of compressed carbon dioxide for use as propulsion in zero-gravity areas. Painted black to indicate that it should not be used as a source for internals."
distribute_pressure = 0
icon_state = "jetpack-black"
item_state = "jetpack-black"
gas_type = "carbon dioxide"
/obj/item/tank/jetpack/suit
name = "hardsuit jetpack upgrade"
desc = "A modular, compact set of thrusters designed to integrate with a hardsuit. It is fueled by a tank inserted into the suit's storage compartment."
icon_state = "jetpack-mining"
item_state = "jetpack-black"
origin_tech = "materials=4;magnets=4;engineering=5"
w_class = WEIGHT_CLASS_NORMAL
actions_types = list(/datum/action/item_action/toggle_jetpack, /datum/action/item_action/jetpack_stabilization)
volume = 1
slot_flags = null
gas_type = null
var/datum/gas_mixture/temp_air_contents
var/obj/item/tank/internals/tank = null
var/mob/living/carbon/human/cur_user
/obj/item/tank/jetpack/suit/New()
..()
STOP_PROCESSING(SSobj, src)
temp_air_contents = air_contents
/obj/item/tank/jetpack/suit/attack_self__legacy__attackchain()
return
/obj/item/tank/jetpack/suit/cycle(mob/user)
if(!istype(loc, /obj/item/clothing/suit/space/hardsuit))
to_chat(user, "<span class='warning'>[src] must be connected to a hardsuit!</span>")
return
var/mob/living/carbon/human/H = user
if(!istype(H.s_store, /obj/item/tank))
to_chat(user, "<span class='warning'>You need a tank in your suit storage!</span>")
return
..()
/obj/item/tank/jetpack/suit/turn_on(mob/user)
if(!istype(loc, /obj/item/clothing/suit/space/hardsuit) || !ishuman(loc.loc) || loc.loc != user)
return
var/mob/living/carbon/human/H = user
tank = H.s_store
air_contents = tank.air_contents
START_PROCESSING(SSobj, src)
cur_user = user
..()
/obj/item/tank/jetpack/suit/turn_off(mob/user)
tank = null
air_contents = temp_air_contents
STOP_PROCESSING(SSobj, src)
cur_user = null
..()
/obj/item/tank/jetpack/suit/process()
if(!istype(loc, /obj/item/clothing/suit/space/hardsuit) || !ishuman(loc.loc))
turn_off(cur_user)
return
var/mob/living/carbon/human/H = loc.loc
if(!tank || tank != H.s_store)
turn_off(cur_user)
return
..()
@@ -1,217 +0,0 @@
/* Types of tanks!
* Contains:
* Oxygen
* Anesthetic
* Air
* Plasma
* Emergency Oxygen
* Generic
*/
/*
* Oxygen
*/
/obj/item/tank/internals
name = "internals tank"
desc = "A tank for use in internals. If you see this, please submit a bug report."
icon_state = "generic"
distribute_pressure = TANK_DEFAULT_RELEASE_PRESSURE
force = 10
/obj/item/tank/internals/oxygen
name = "oxygen tank"
desc = "A tank of oxygen. This one is blue."
icon_state = "oxygen"
dog_fashion = /datum/dog_fashion/back
/obj/item/tank/internals/oxygen/populate_gas()
air_contents.set_oxygen((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/oxygen/yellow
desc = "A tank of oxygen, this one is yellow."
icon_state = "oxygen_f"
/obj/item/tank/internals/oxygen/red
desc = "A tank of oxygen, this one is red."
icon_state = "oxygen_fr"
/obj/item/tank/internals/oxygen/empty/populate_gas()
return
/*
* Anesthetic
*/
/obj/item/tank/internals/anesthetic
name = "anesthetic tank"
desc = "A tank with an N2O/O2 gas mix."
icon_state = "anesthetic"
item_state = "an_tank"
distribute_pressure = ONE_ATMOSPHERE
/obj/item/tank/internals/anesthetic/populate_gas()
air_contents.set_oxygen((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * O2STANDARD)
air_contents.set_sleeping_agent((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * N2STANDARD)
/*
* Plasma
*/
/obj/item/tank/internals/plasma
name = "plasma tank"
desc = "Contains dangerous plasma. Do not inhale. Warning: extremely flammable."
icon_state = "plasma"
slot_flags = null //they have no straps!
force = 8
/obj/item/tank/internals/plasma/populate_gas()
air_contents.set_toxins((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/plasma/attackby__legacy__attackchain(obj/item/I, mob/user, params)
if(istype(I, /obj/item/flamethrower))
var/obj/item/flamethrower/F = I
if((!F.status)||(F.ptank))
return
master = F
F.ptank = src
user.transfer_item_to(src, F)
F.update_icon()
else
return ..()
/obj/item/tank/internals/plasma/full/populate_gas()
air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/plasma/empty/populate_gas()
return
/*
* Plasmaman Plasma Tank
*/
/obj/item/tank/internals/plasmaman
name = "plasma internals tank"
desc = "A tank of plasma gas designed specifically for use as internals, particularly for plasma-based lifeforms. If you're not a Plasmaman, you probably shouldn't use this."
icon_state = "plasma_fr"
item_state = "plasma_fr"
/obj/item/tank/internals/plasmaman/populate_gas()
air_contents.set_toxins((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/plasmaman/full/populate_gas()
air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/plasmaman/belt
icon_state = "plasmaman_tank_belt"
item_state = "plasmaman_tank_belt"
slot_flags = ITEM_SLOT_BELT
flags_2 = ALLOW_BELT_NO_JUMPSUIT_2
force = 5
volume = 18 // Lasts 1h 16m 30s
w_class = WEIGHT_CLASS_SMALL
/obj/item/tank/internals/plasmaman/belt/full/populate_gas()
air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/plasmaman/belt/empty/populate_gas()
return
/obj/item/tank/internals/emergency_oxygen/plasma
name = "emergency plasma tank"
desc = "An emergency tank designed specifically for Plasmamen."
icon_state = "emergency_p"
/obj/item/tank/internals/emergency_oxygen/plasma/populate_gas()
air_contents.set_toxins((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/*
* Emergency Oxygen
*/
/obj/item/tank/internals/emergency_oxygen
name = "emergency oxygen tank"
desc = "Used for emergencies. Contains very little oxygen, so try to conserve it until you actually need it."
icon_state = "emergency"
slot_flags = ITEM_SLOT_BELT
flags_2 = ALLOW_BELT_NO_JUMPSUIT_2
w_class = WEIGHT_CLASS_SMALL
force = 4
volume = 1 // Roughly 4m 15s of air
/obj/item/tank/internals/emergency_oxygen/populate_gas()
air_contents.set_oxygen((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/emergency_oxygen/empty/populate_gas()
return
/obj/item/tank/internals/emergency_oxygen/engi
name = "extended-capacity emergency oxygen tank"
icon_state = "emergency_engi"
volume = 3 // Lasts 12m 45s
/obj/item/tank/internals/emergency_oxygen/engi/empty/populate_gas()
return
/obj/item/tank/internals/emergency_oxygen/engi/syndi
name = "suspicious emergency oxygen tank"
icon_state = "emergency_syndi"
desc = "A dark emergency oxygen tank. The label on the back reads \"Original Oxygen Tank Design, Do Not Steal.\""
volume = 11 // Lasts 46m 45s
/obj/item/tank/internals/emergency_oxygen/double
name = "double emergency oxygen tank"
icon_state = "emergency_double"
volume = 6 // Lasts 25m 30s
/obj/item/tank/internals/emergency_oxygen/double/empty/populate_gas()
return
/*
* Nitrogen
*/
/obj/item/tank/internals/nitrogen
name = "nitrogen tank"
desc = "A tank of nitrogen."
icon_state = "oxygen_fr"
/obj/item/tank/internals/nitrogen/populate_gas()
air_contents.set_nitrogen((6 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/emergency_oxygen/nitrogen
name = "emergency nitrogen tank"
desc = "An emergency tank designed specifically for Vox."
icon_state = "emergency_nitrogen"
/obj/item/tank/internals/emergency_oxygen/nitrogen/populate_gas()
air_contents.set_nitrogen((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/obj/item/tank/internals/emergency_oxygen/double/vox
name = "vox specialized nitrogen tank"
desc = "A high-tech nitrogen tank designed specifically for Vox."
icon_state = "emergency_vox"
volume = 18 // Lasts 1h 16m 30s
/obj/item/tank/internals/emergency_oxygen/double/vox/populate_gas()
air_contents.set_nitrogen((10 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C))
/*
* Air Mix
*/
/obj/item/tank/internals/air
name = "air tank"
desc = "Mixed anyone?"
icon_state = "air"
item_state = "air"
distribute_pressure = ONE_ATMOSPHERE
/obj/item/tank/internals/air/populate_gas()
air_contents.set_oxygen((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * O2STANDARD)
air_contents.set_nitrogen((3 * ONE_ATMOSPHERE) * volume / (R_IDEAL_GAS_EQUATION * T20C) * N2STANDARD)
/*
* Generic
*/
/obj/item/tank/internals/generic
name = "gas tank"
desc = "A generic tank used for storing and transporting gasses. Can be used for internals."
item_state = "generic"
/obj/item/tank/internals/generic/populate_gas()
return
@@ -1,373 +0,0 @@
//Hydroponics tank and base code
/obj/item/watertank
name = "backpack water tank"
desc = "A S.U.N.S.H.I.N.E. brand watertank backpack with nozzle to water plants."
icon = 'icons/obj/watertank.dmi'
icon_state = "waterbackpack"
item_state = "waterbackpack"
w_class = WEIGHT_CLASS_BULKY
slot_flags = ITEM_SLOT_BACK
slowdown = 1
actions_types = list(/datum/action/item_action/toggle_mister)
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 100, ACID = 30)
resistance_flags = FIRE_PROOF
var/obj/item/noz
var/on = FALSE
var/volume = 500
/obj/item/watertank/New()
..()
create_reagents(volume)
noz = make_noz()
/obj/item/watertank/Destroy()
if(on)
remove_noz()
QDEL_NULL(noz)
return ..()
/obj/item/watertank/ui_action_click(mob/user)
toggle_mister(user)
/obj/item/watertank/item_action_slot_check(slot, mob/user)
if(slot == ITEM_SLOT_BACK)
return TRUE
/obj/item/watertank/proc/toggle_mister(mob/user)
if(user.stat || HAS_TRAIT(user, TRAIT_HANDS_BLOCKED) || !Adjacent(user))
return
if(user.get_item_by_slot(ITEM_SLOT_BACK) != src)
to_chat(user, "<span class='notice'>The watertank needs to be on your back to use.</span>")
return
on = !on
if(on)
if(!noz)
noz = make_noz()
//Detach the nozzle into the user's hands
if(!user.put_in_hands(noz))
on = FALSE
to_chat(user, "<span class='notice'>You need a free hand to hold the mister.</span>")
return
noz.forceMove(user)
else
//Remove from their hands and put back "into" the tank
remove_noz()
return
/obj/item/watertank/proc/make_noz()
return new /obj/item/reagent_containers/spray/mister(src)
/obj/item/watertank/equipped(mob/user, slot)
..()
if(slot != ITEM_SLOT_BACK)
remove_noz()
/obj/item/watertank/proc/remove_noz()
if(ismob(noz.loc))
var/mob/M = noz.loc
M.drop_item_to_ground(noz, force = TRUE)
return
/obj/item/watertank/attack_hand(mob/user)
if(loc == user)
toggle_mister(user)
return
..()
/obj/item/watertank/MouseDrop(obj/over_object)
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
switch(over_object.name)
if("r_hand")
if(H.r_hand)
return
if(!H.unequip(src))
return
H.put_in_r_hand(src)
if("l_hand")
if(H.l_hand)
return
if(!H.unequip(src))
return
H.put_in_l_hand(src)
return
/obj/item/watertank/attackby__legacy__attackchain(obj/item/W, mob/user, params)
if(W == noz)
remove_noz()
return
..()
// This mister item is intended as an extension of the watertank and always attached to it.
// Therefore, it's designed to be "locked" to the player's hands or extended back onto
// the watertank backpack. Allowing it to be placed elsewhere or created without a parent
// watertank object will likely lead to weird behaviour or runtimes.
/obj/item/reagent_containers/spray/mister
name = "water mister"
desc = "A mister nozzle attached to a water tank."
icon = 'icons/obj/watertank.dmi'
icon_state = "mister"
item_state = "mister"
w_class = WEIGHT_CLASS_BULKY
amount_per_transfer_from_this = 50
possible_transfer_amounts = list(25,50,100)
volume = 500
var/obj/item/watertank/tank
/obj/item/reagent_containers/spray/mister/Initialize(mapload)
if(!check_tank_exists(loc, src))
return INITIALIZE_HINT_QDEL
tank = loc
reagents = tank.reagents //This mister is really just a proxy for the tank's reagents
RegisterSignal(src, COMSIG_ACTIVATE_SELF, TYPE_PROC_REF(/datum, signal_cancel_activate_self))
return ..()
/obj/item/reagent_containers/spray/mister/Destroy()
tank = null
reagents = null // Unset, this is the tanks reagents
return ..()
/obj/item/reagent_containers/spray/mister/dropped(mob/user as mob)
..()
to_chat(user, "<span class='notice'>The mister snaps back onto the watertank.</span>")
tank.on = FALSE
loc = tank
/proc/check_tank_exists(parent_tank, mob/living/carbon/human/M, obj/O)
if(!parent_tank || (!istype(parent_tank, /obj/item/watertank) && !istype(parent_tank, /obj/item/mod/module/firefighting_tank))) //To avoid weird issues from admin spawns
return FALSE
else
return TRUE
/obj/item/reagent_containers/spray/mister/Move()
..()
if(loc != tank.loc)
loc = tank.loc
/obj/item/reagent_containers/spray/mister/normal_act(atom/target, mob/living/user)
if(target.loc == loc || target == tank)
return FALSE
return ..()
//Janitor tank
/obj/item/watertank/janitor
desc = "A janitorial watertank backpack with nozzle to clean dirt and graffiti."
icon_state = "waterbackpackjani"
item_state = "waterbackpackjani"
/obj/item/watertank/janitor/New()
..()
reagents.add_reagent("cleaner", 500)
/obj/item/reagent_containers/spray/mister/janitor
name = "janitor spray nozzle"
desc = "A janitorial spray nozzle attached to a watertank, designed to clean up large messes."
icon_state = "misterjani"
item_state = "misterjani"
spray_maxrange = 4
spray_currentrange = 4
amount_per_transfer_from_this = 10
possible_transfer_amounts = null
/obj/item/watertank/janitor/make_noz()
return new /obj/item/reagent_containers/spray/mister/janitor(src)
/obj/item/reagent_containers/spray/mister/janitor/activate_self(mob/user)
if(..())
return FINISH_ATTACK
amount_per_transfer_from_this = (amount_per_transfer_from_this == 5 ? 10 : 5)
spray_currentrange = (spray_currentrange == 2 ? spray_maxrange : 2)
to_chat(user, "<span class='notice'>You [amount_per_transfer_from_this == 5 ? "remove" : "fix"] the nozzle. You'll now use [amount_per_transfer_from_this] units per spray.</span>")
//ATMOS FIRE FIGHTING BACKPACK
#define EXTINGUISHER 0
#define NANOFROST 1
#define METAL_FOAM 2
/obj/item/watertank/atmos
name = "backpack firefighter tank"
desc = "A refridgerated and pressurized backpack tank with extinguisher nozzle, intended to fight fires. Swaps between extinguisher, nanofrost launcher, and metal foam dispenser for breaches. Nanofrost converts plasma in the air to nitrogen, but only if it is combusting at the time."
icon_state = "waterbackpackatmos"
item_state = "waterbackpackatmos"
/obj/item/watertank/atmos/New()
..()
reagents.add_reagent("water", 500)
/obj/item/watertank/atmos/make_noz()
return new /obj/item/extinguisher/mini/nozzle(src)
/obj/item/watertank/atmos/dropped(mob/user as mob)
..()
icon_state = "waterbackpackatmos"
if(istype(noz, /obj/item/extinguisher/mini/nozzle))
var/obj/item/extinguisher/mini/nozzle/N = noz
N.nozzle_mode = 0
/obj/item/extinguisher/mini/nozzle
name = "extinguisher nozzle"
desc = "A heavy duty nozzle attached to a firefighter's backpack tank."
icon = 'icons/obj/watertank.dmi'
icon_state = "atmos_nozzle_1"
item_state = "nozzleatmos"
has_safety = FALSE
safety_active = FALSE
reagent_capacity = 500
precision = TRUE
cooling_power = 5
w_class = WEIGHT_CLASS_HUGE
flags = NODROP //Necessary to ensure that the nozzle and tank never seperate
/// A reference to the tank that this nozzle is linked to
var/obj/item/watertank/tank
/// What mode are we currently in?
var/nozzle_mode = EXTINGUISHER
/// How many shots of metal foam do we have?
var/metal_synthesis_charge = 5
/// Time to refill 1 charge of metal foam.
var/metal_regen_time = 2 SECONDS
/// Refire delay for nanofrost chunks.
var/nanofrost_cooldown_time = 2 SECONDS
COOLDOWN_DECLARE(nanofrost_cooldown)
/obj/item/extinguisher/mini/nozzle/examine(mob/user)
. = ..()
switch(nozzle_mode)
if(EXTINGUISHER)
. += "<span class='notice'>[src] is currently set to extinguishing mode.</span>"
if(NANOFROST)
. += "<span class='notice'>[src] is currently set to nanofrost mode.</span>"
if(METAL_FOAM)
. += "<span class='notice'>[src] is currently set to metal foam mode.</span>"
/obj/item/extinguisher/mini/nozzle/Initialize(mapload)
if(!check_tank_exists(loc, src))
return INITIALIZE_HINT_QDEL
tank = loc
reagents = tank.reagents
reagent_capacity = tank.volume
return ..()
/obj/item/extinguisher/mini/nozzle/Destroy()
tank = null
reagents = null // Unset, this is the tanks reagents
return ..()
/obj/item/extinguisher/mini/nozzle/Move()
..()
if(tank && loc != tank.loc)
forceMove(tank)
/obj/item/extinguisher/mini/nozzle/activate_self(mob/user)
..()
switch(nozzle_mode)
if(EXTINGUISHER)
nozzle_mode = NANOFROST
to_chat(user, "Swapped to nanofrost launcher")
if(NANOFROST)
nozzle_mode = METAL_FOAM
to_chat(user, "Swapped to metal foam synthesizer")
if(METAL_FOAM)
nozzle_mode = EXTINGUISHER
to_chat(user, "Swapped to water extinguisher")
update_icon(UPDATE_ICON_STATE)
return ITEM_INTERACT_COMPLETE
/obj/item/extinguisher/mini/nozzle/update_icon_state()
switch(nozzle_mode)
if(EXTINGUISHER)
icon_state = "atmos_nozzle_1"
tank.icon_state = "waterbackpackatmos_0"
if(NANOFROST)
icon_state = "atmos_nozzle_2"
tank.icon_state = "waterbackpackatmos_1"
if(METAL_FOAM)
icon_state = "atmos_nozzle_3"
tank.icon_state = "waterbackpackatmos_2"
/obj/item/extinguisher/mini/nozzle/dropped(mob/user)
..()
if(istype(tank, /obj/item/mod/module/firefighting_tank))
return
to_chat(user, "<span class='notice'>The nozzle snaps back onto the tank!</span>")
tank.on = FALSE
loc = tank
/obj/item/extinguisher/mini/nozzle/extinguisher_spray(atom/A, mob/living/user)
if(nozzle_mode == EXTINGUISHER)
return ..()
. = TRUE
switch(nozzle_mode)
if(NANOFROST)
if(reagents.total_volume < 100)
to_chat(user, "<span class='warning'>You need at least 100 units of water to use the nanofrost launcher!</span>")
return
if(COOLDOWN_TIMELEFT(src, nanofrost_cooldown))
to_chat(user, "<span class='warning'>The nanofrost launcher is still recharging!</span>")
return
COOLDOWN_START(src, nanofrost_cooldown, nanofrost_cooldown_time)
reagents.remove_any(100)
var/obj/effect/nanofrost_container/iceball = new /obj/effect/nanofrost_container(get_turf(src))
log_game("[key_name(user)] used Nanofrost at [get_area(user)] ([user.x], [user.y], [user.z]).")
playsound(src,'sound/items/syringeproj.ogg', 40, TRUE)
iceball.throw_at(A, 6, 2, user)
sleep(2)
iceball.Smoke()
return
if(METAL_FOAM)
if(!user.Adjacent(A) || !isturf(A))
return
if(metal_synthesis_charge <= 0)
to_chat(user, "<span class='warning'>Metal foam mix is still being synthesized!</span>")
return
if(reagents.total_volume < 10)
to_chat(user, "<span class='warning'>You need at least 10 units of water to use the metal foam synthesizer!</span>")
return
var/obj/effect/particle_effect/foam/metal/foam = new /obj/effect/particle_effect/foam/metal(get_turf(A), TRUE)
foam.spread_amount = 0
reagents.remove_any(10)
metal_synthesis_charge--
addtimer(CALLBACK(src, PROC_REF(refill_metal_charge)), metal_regen_time)
return
/obj/item/extinguisher/mini/nozzle/proc/refill_metal_charge()
metal_synthesis_charge++
/obj/effect/nanofrost_container
name = "nanofrost container"
desc = "A frozen shell of ice containing nanofrost that freezes the surrounding area after activation."
icon_state = "frozen_smoke_capsule"
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
pass_flags = PASSTABLE
/obj/effect/nanofrost_container/proc/Smoke()
var/datum/effect_system/smoke_spread/freezing/S = new
S.set_up(amount = 6, only_cardinals = FALSE, source = loc)
S.start()
new /obj/effect/decal/cleanable/flour/nanofrost(get_turf(src))
playsound(src, 'sound/effects/bamf.ogg', 100, TRUE)
qdel(src)
/obj/effect/nanofrost_container/anomaly
name = "nanofrost anomaly"
desc = "A frozen shell of ice containing nanofrost that freezes the surrounding area."
icon_state = "frozen_smoke_anomaly"
#undef EXTINGUISHER
#undef NANOFROST
#undef METAL_FOAM
-55
View File
@@ -1,55 +0,0 @@
/obj/item/stack/tape_roll
name = "tape roll"
desc = "A roll of sticky tape. Possibly for taping ducks... or was that ducts?"
icon = 'icons/obj/bureaucracy.dmi'
icon_state = "taperoll"
singular_name = "tape roll"
w_class = WEIGHT_CLASS_TINY
amount = 25
max_amount = 25
/obj/item/stack/tape_roll/New(loc, amount=null)
..()
update_icon(UPDATE_ICON_STATE)
/obj/item/stack/tape_roll/attack__legacy__attackchain(mob/living/carbon/human/M, mob/living/user)
if(!istype(M)) //What good is a duct tape mask if you are unable to speak?
return
if(M.wear_mask)
to_chat(user, "Remove [M.p_their()] mask first!")
return
if(amount < 2)
to_chat(user, "You'll need more tape for this!")
return
if(!M.check_has_mouth())
to_chat(user, "[M.p_they(TRUE)] [M.p_have()] no mouth to tape over!")
return
user.visible_message("<span class='warning'>[user] is taping [M]'s mouth closed!</span>",
"<span class='notice'>You try to tape [M == user ? "your own" : "[M]'s"] mouth shut!</span>",
"<span class='warning'>You hear tape ripping.</span>")
if(!do_after(user, 50, target = M))
return
if(!use(2))
to_chat(user, "<span class='notice'>You don't have enough tape!</span>")
return
if(M.wear_mask)
to_chat(user, "<span class='notice'>[M == user ? user : M]'s mouth is already covered!</span>")
return
user.visible_message("<span class='warning'>[user] tapes [M]'s mouth shut!</span>",
"<span class='notice'>You cover [M == user ? "your own" : "[M]'s"] mouth with a piece of duct tape.[M == user ? null : " That will shut them up."]</span>")
var/obj/item/clothing/mask/muzzle/G = new /obj/item/clothing/mask/muzzle/tapegag
M.equip_to_slot(G, ITEM_SLOT_MASK)
G.add_fingerprint(user)
/obj/item/stack/tape_roll/update_icon_state()
var/amount = get_amount()
if((amount <= 2) && (amount > 0))
icon_state = "taperoll"
if((amount <= 4) && (amount > 2))
icon_state = "taperoll-2"
if((amount <= 6) && (amount > 4))
icon_state = "taperoll-3"
if(amount > 6)
icon_state = "taperoll-4"
else
icon_state = "taperoll-4"
@@ -1,109 +0,0 @@
/* Teleportation devices.
* Contains:
* Hand-tele
*/
/*
* Hand-tele
*/
/obj/item/hand_tele
name = "hand tele"
desc = "An experimental portable teleportation station developed by Nanotrasen, small enough to be carried in a pocket."
icon = 'icons/obj/device.dmi'
icon_state = "hand_tele"
item_state = "electronic"
w_class = WEIGHT_CLASS_SMALL
throw_speed = 3
throw_range = 5
materials = list(MAT_METAL=10000)
origin_tech = null
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 30, RAD = 0, FIRE = 100, ACID = 100)
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ACID_PROOF
var/icon_state_inactive = "hand_tele_inactive"
/// The number of open teleportals.
var/active_portals = 0
/// Variable contains next time hand tele can be used to make it not EMP proof
var/emp_timer = 0
/obj/item/hand_tele/examine_more(mob/user)
. = ..()
. += "Conventional teleportation technology requires either inflexible quantum pad setups that can only send users between two fixed locations, \
or large immobile portal generators connected to an even larger set of computer equipment that is required for safe translation through extradimensional space."
. += ""
. += "This specialised portable teleporter is an experimental miniaturisation of the latter category. It utilises highly specialised analogue circuitry to perform the bulk of the teleportation calculations, \
allowing for a far more compact package than more generalised digital computer technology would allow. Some digital components are present, which handle the user interface and beacon tracking functions. \
In order to allow the device to be fully portable, it has no frame to stabilise the portals it generates. This comes at the cost of the portals only being able to persist for a limited time."
. += ""
. += "A limited number of these experimental devices exist. Due manufacturing difficulties (particularly regarding the analogue computer), \
Nanotrasen has delayed releasing it onto the market until it can improve its production methods."
/obj/item/hand_tele/Initialize(mapload)
. = ..()
AddElement(/datum/element/high_value_item)
/obj/item/hand_tele/attack_self__legacy__attackchain(mob/user)
// The turf the user is currently located in.
var/turf/current_location = get_turf(user)
if(emp_timer > world.time)
do_sparks(5, 0, loc)
to_chat(user, "<span class='warning'>[src] attempts to create a portal, but abruptly shuts off.</span>")
return
if(!current_location||!is_teleport_allowed(current_location.z))//If turf was not found or they're somewhere teleproof
to_chat(user, "<span class='notice'>\The [src] is malfunctioning.</span>")
return
var/list/L = list()
for(var/obj/machinery/computer/teleporter/com in SSmachines.get_by_type(/obj/machinery/computer/teleporter))
if(com.target)
if(com.power_station && com.power_station.teleporter_hub && com.power_station.engaged)
L["[com.id] (Active)"] = com.target
else
L["[com.id] (Inactive)"] = com.target
var/list/turfs = list()
var/area/A
for(var/turf/T in orange(10))
if(T.x>world.maxx-8 || T.x<8)
continue //putting them at the edge is dumb
if(T.y>world.maxy-8 || T.y<8)
continue
A = get_area(T)
if(A.tele_proof)
continue // Telescience-proofed areas require a beacon.
turfs += T
if(length(turfs))
L["None (Dangerous)"] = pick(turfs)
flick("hand_tele_activated", src)
var/t1 = tgui_input_list(user, "Please select a teleporter to lock in on.", "Hand Teleporter", L)
if(!t1 || (!user.is_in_active_hand(src) || user.stat || user.restrained()))
return
if(active_portals >= 3)
user.show_message("<span class='notice'>\The [src] is recharging!</span>")
return
var/T = L[t1]
user.show_message("<span class='notice'>Locked In.</span>", 2)
var/obj/effect/portal/P = new /obj/effect/portal/hand_tele(get_turf(src), T, src, creation_mob = user)
try_move_adjacent(P)
active_portals++
add_fingerprint(user)
/obj/item/hand_tele/emp_act(severity)
make_inactive(severity)
return ..()
/obj/item/hand_tele/proc/make_inactive(severity)
icon_state = icon_state_inactive
var/time = rand(25 SECONDS, 30 SECONDS) * severity
emp_timer = world.time + time
addtimer(CALLBACK(src, PROC_REF(check_inactive), emp_timer), time)
/obj/item/hand_tele/proc/check_inactive(current_emp_timer)
if(emp_timer != current_emp_timer)
return
icon_state = initial(icon_state)
/obj/item/hand_tele/examine(mob/user)
. = ..()
if(emp_timer > world.time)
. += "<span class='warning'>It looks inactive.</span>"
/obj/item/hand_tele/portal_destroyed(obj/effect/portal/P)
active_portals--
@@ -1,234 +0,0 @@
/obj/item/vending_refill
name = "resupply canister"
var/machine_name = "Generic"
icon = 'icons/obj/vending_restock.dmi'
icon_state = "refill_snack"
item_state = "restock_unit"
desc = "A vending machine restock cart."
usesound = 'sound/items/deconstruct.ogg'
flags = CONDUCT
force = 7
throwforce = 10
throw_speed = 1
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, RAD = 0, FIRE = 70, ACID = 30)
// Built automatically from the corresponding vending machine.
// If null, considered to be full upon being restocked.
var/list/products
var/list/contraband
var/list/premium
/obj/item/vending_refill/Initialize(mapload)
. = ..()
name = "\improper [machine_name] restocking unit"
/obj/item/vending_refill/examine(mob/user)
. = ..()
var/num = get_part_rating()
if(num == INFINITY)
. += "It's sealed tight, completely full of supplies."
else if(num == 0)
. += "It's empty!"
else if(!isnull(num)) // If it's null, then the items haven't been properly added yet.
. += "It can restock [num] item\s."
/obj/item/vending_refill/get_part_rating()
. = 0
if(isnull(products) && isnull(contraband) && isnull(premium))
return null
for(var/key in products)
. += products[key]
for(var/key in contraband)
. += contraband[key]
for(var/key in premium)
. += premium[key]
if(. > 30)
return INFINITY
/obj/item/vending_refill/boozeomat
machine_name = "Booze-O-Mat"
icon_state = "refill_booze"
/obj/item/vending_refill/coffee
machine_name = "hot drinks"
icon_state = "refill_joe"
/obj/item/vending_refill/snack
machine_name = "Getmore Chocolate Corp"
/obj/item/vending_refill/cola
machine_name = "Robust Softdrinks"
icon_state = "refill_cola"
/obj/item/vending_refill/cigarette
machine_name = "cigarette"
icon_state = "refill_smoke"
/obj/item/vending_refill/autodrobe
machine_name = "AutoDrobe"
icon_state = "refill_costume"
/obj/item/vending_refill/hatdispenser
machine_name = "hat"
icon_state = "refill_costume"
/obj/item/vending_refill/suitdispenser
machine_name = "suit"
icon_state = "refill_costume"
/obj/item/vending_refill/shoedispenser
machine_name = "shoe"
icon_state = "refill_costume"
/obj/item/vending_refill/clothing
machine_name = "ClothesMate"
icon_state = "refill_clothes"
/obj/item/vending_refill/crittercare
machine_name = "CritterCare"
icon_state = "refill_pet"
/obj/item/vending_refill/chinese
machine_name = "MrChangs"
/obj/item/vending_refill/hydroseeds
machine_name = "MegaSeed Servitor"
icon_state = "refill_plant"
/obj/item/vending_refill/assist
machine_name = "Vendomat"
icon_state = "refill_engi"
/obj/item/vending_refill/cart
machine_name = "PTech"
icon_state = "refill_smoke"
/obj/item/vending_refill/dinnerware
machine_name = "Plasteel Chef's Dinnerware Vendor"
icon_state = "refill_smoke"
/obj/item/vending_refill/engineering
machine_name = "Robco Tool Maker"
icon_state = "refill_engi"
/obj/item/vending_refill/youtool
machine_name = "YouTool"
icon_state = "refill_engi"
/obj/item/vending_refill/engivend
machine_name = "Engi-Vend"
icon_state = "refill_engi"
/obj/item/vending_refill/medical
machine_name = "NanoMed Plus"
icon_state = "refill_medical"
/obj/item/vending_refill/wallmed
machine_name = "NanoMed"
icon_state = "refill_medical"
/obj/item/vending_refill/hydronutrients
machine_name = "NutriMax"
icon_state = "refill_plant"
/obj/item/vending_refill/security
icon_state = "refill_sec"
/obj/item/vending_refill/sovietsoda
machine_name = "BODA"
icon_state = "refill_cola"
/obj/item/vending_refill/sustenance
machine_name = "Sustenance Vendor"
/obj/item/vending_refill/donksoft
machine_name = "Donksoft Toy Vendor"
icon_state = "refill_donksoft"
/obj/item/vending_refill/robotics
machine_name = "Robotech Deluxe"
icon_state = "refill_engi"
/obj/item/vending_refill/smith
machine_name = "Castivend"
icon_state = "refill_custom"
//Departmental clothing vendors
/obj/item/vending_refill/secdrobe
machine_name = "SecDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/detdrobe
machine_name = "DetDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/medidrobe
machine_name = "MediDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/virodrobe
machine_name = "ViroDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/chemdrobe
machine_name = "ChemDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/genedrobe
machine_name = "GeneDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/scidrobe
machine_name = "SciDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/robodrobe
machine_name = "RoboDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/engidrobe
machine_name = "EngiDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/atmosdrobe
machine_name = "AtmosDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/cargodrobe
machine_name = "CargoDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/exploredrobe
machine_name = "ExploreDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/chefdrobe
machine_name = "ChefDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/bardrobe
machine_name = "BarDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/hydrodrobe
machine_name = "HydroDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/janidrobe
machine_name = "JaniDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/lawdrobe
machine_name = "LawDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/traindrobe
machine_name = "TrainDrobe"
icon_state = "refill_clothes"
/obj/item/vending_refill/minedrobe
machine_name = "MineDrobe"
icon_state = "refill_clothes"