Bugfix batch (Pesticide Edition) (#21556)

Fixes https://github.com/Aurorastation/Aurora.3/issues/18504
Fixes https://github.com/Aurorastation/Aurora.3/issues/21064
Fixes https://github.com/Aurorastation/Aurora.3/issues/21267
Fixes https://github.com/Aurorastation/Aurora.3/issues/21455
Fixes https://github.com/Aurorastation/Aurora.3/issues/21535

Miscellaneous bugfixes, code cleanup, etc. Smaller batches this time.

changes:
  - spellcheck: "Renames 'gibber' to 'autobutcher'."
  - code_imp: "Cleans up a lot of old autobutcher code."
- code_imp: "Simplifies and unifies a lot of circuit board naming code."
  - code_imp: "Updates various code comments to DMDocs format."
- balance: "Slightly increased damage of beating someone with a ladder."
- bugfix: "Fixes foreign speech displaying the translated versions in
langchat for non-fluent listeners."
- bugfix: "Fixes whispered speech langchat; whispers are now correctly
italicized."
- bugfix: "Fixes shouted speech langchat; shouts are now correctly
biggified."
  - bugfix: "Adds missing Omni Gas Mixer, Gas Meter options from RFD-P."
- bugfix: "Adds missing circuit boards for bioballistic delivery system,
lysis-isolation centrifuge, and autobutcher to allow for construction
and deconstruction."
- bugfix: "Fixes empty algae chips bag having description set for its
name."
- bugfix: "Adds fallback_specific_heat values to several reagents that
were missing them."
- bugfix: "Fixes antimateriel projectiles being erroneously
damage-capped when hitting walls."
- bugfix: "Fixes laser beam effects not using the base colors of their
beam VFX."
- qol: "Added helpful feedback hint to move closer when someone speaks
aloud within 4 tiles while you're in vacuum (as features go, this one
felt more like a bug to experience)."
  - qol: "Updated various examine hints."

---------

Signed-off-by: Batrachophreno <Batrochophreno@gmail.com>
This commit is contained in:
Batrachophreno
2025-11-11 10:56:12 +00:00
committed by GitHub
parent cc8e3019ad
commit af0312c7d4
67 changed files with 559 additions and 432 deletions
+4 -4
View File
@@ -138,7 +138,7 @@
/singleton/cargo_item/circuitboard_bubbleshield
category = "engineering"
name = "circuit board (bubble shield generator)"
name = T_BOARD("bubble shield generator")
supplier = "hephaestus"
description = "Looks like a circuit. Probably is."
price = 250
@@ -152,7 +152,7 @@
/singleton/cargo_item/circuitboard_hullshield
category = "engineering"
name = "circuit board (hull shield generator)"
name = T_BOARD("hull shield generator")
supplier = "hephaestus"
description = "Looks like a circuit. Probably is."
price = 250
@@ -166,7 +166,7 @@
/singleton/cargo_item/circuitboard_shieldcapacitor
category = "engineering"
name = "circuit board (shield capacitor)"
name = T_BOARD("shield capacitor")
supplier = "hephaestus"
description = "Looks like a circuit. Probably is."
price = 250
@@ -180,7 +180,7 @@
/singleton/cargo_item/circuitboard_solarcontrol
category = "engineering"
name = "circuit board (solar control console)"
name = T_BOARD("solar control console")
supplier = "hephaestus"
description = "Looks like a circuit. Probably is."
price = 250
@@ -5,13 +5,13 @@
var/icon_base = null
w_class = WEIGHT_CLASS_BULKY
///The type of board, a path of `/obj/item/circuitboard`
/// The type of board, a path of `/obj/item/circuitboard`
var/board_type = null
///The type of target board, a path of `/obj/item/circuitboard`
/// The type of target board, a path of `/obj/item/circuitboard`
var/target_board_type = null
///The type of rig, a path of `/obj/item/rig`
/// The type of rig, a path of `/obj/item/rig`
var/rig_type = /obj/item/rig
obj_flags = OBJ_FLAG_CONDUCTABLE
+74 -34
View File
@@ -1,27 +1,40 @@
/obj/machinery/gibber
name = "gibber"
desc = "The name isn't descriptive enough?"
desc_extended = "WARNING : Insurance no longer covers entertaining intrusive thoughts. Keep your limbs to yourself."
name = "autobutcher"
desc = "Also known as the gibber, affectionately."
desc_extended = "WARNING: Insurance no longer covers entertaining intrusive thoughts. Keep your limbs to yourself."
icon = 'icons/obj/machinery/cooking_machines.dmi'
icon_state = "grinder"
density = 1
density = TRUE
anchored = TRUE
req_access = list(ACCESS_GALLEY,ACCESS_MORGUE)
var/operating = 0 //Is it on?
var/dirty = 0 // Does it need cleaning?
var/mob/living/occupant // Mob who has been put inside
var/gib_time = 40 // Time from starting until meat appears
var/gib_throw_dir = WEST // Direction to spit meat and gibs in.
/// Is it on?
var/operating = FALSE
/// Does it need cleaning?
var/dirty = FALSE
/// Mob who has been put inside
var/mob/living/occupant
/// Time from starting until meat appears
var/gib_time = 4 SECONDS
/// Direction to spit meat and gibs in.
var/gib_throw_dir = WEST
idle_power_usage = 2
active_power_usage = 500
//auto-gibs anything that bumps into it
/// Auto-gibs anything that moves onto its input plate. This is a fun variant, someone map it in somewhere!
/obj/machinery/gibber/autogibber
var/turf/input_plate
/obj/machinery/gibber/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
. += "The safety guard is [emagged ? SPAN_DANGER("disabled") : "enabled"]."
/obj/machinery/gibber/antagonist_hints(mob/user, distance, is_adjacent)
. += ..()
. += "This can be emagged to let you feed people into it; it also removes the ID access requirements."
/obj/machinery/gibber/autogibber/Initialize()
. = ..()
for(var/i in GLOB.cardinals)
@@ -39,16 +52,44 @@
/obj/machinery/gibber/autogibber/CollidedWith(atom/bumped_atom)
. = ..()
if(stat & (NOPOWER|BROKEN))
return FALSE
if(!input_plate)
return
return FALSE
if(!ismob(bumped_atom))
return
var/mob/M = bumped_atom
if(M.loc == input_plate)
M.forceMove(src)
M.gib()
return FALSE
var/mob/victim_mob = bumped_atom
var/mob/living/carbon/human/victim_human
// A lot of reused code here but it's needed to prevent CollidedWith from running DoMob, which makes SpaceDMM sad because of SHOULD_NOT_SLEEP and etc etc etc.
if(ishuman(victim_mob))
victim_human = victim_mob
if(occupant)
if(victim_human.client)
to_chat(victim_human, SPAN_DANGER("[src] is full, you can't fit!"))
return FALSE
if(operating)
if(victim_human.client)
to_chat(victim_human, SPAN_DANGER("[src] is locked and running, it won't let you in!"))
return FALSE
if(ishuman(victim_human) && !emagged)
if(victim_human.client)
to_chat(victim_human, SPAN_DANGER("\The [src]'s safety guard is engaged!"))
return FALSE
if(istype(victim_mob, /mob) && victim_mob.loc == input_plate)
visible_message(SPAN_DANGER("[victim_mob] gets automatically fed into \the [src]!"))
else
return FALSE
if(victim_human.client)
victim_human.client.perspective = EYE_PERSPECTIVE
victim_human.client.eye = src
victim_mob.forceMove(src)
occupant = victim_mob
startgibbing(victim_mob)
update_icon()
/obj/machinery/gibber/Initialize()
. = ..()
@@ -56,11 +97,11 @@
/obj/machinery/gibber/update_icon()
ClearOverlays()
if (dirty)
if(dirty)
AddOverlays("grbloody")
if(stat & (NOPOWER|BROKEN))
return
if (!occupant)
if(!occupant)
AddOverlays("grjam")
else if (operating)
AddOverlays("gruse")
@@ -81,10 +122,6 @@
return
startgibbing(user)
/obj/machinery/gibber/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
. = ..()
. += "The safety guard is [emagged ? SPAN_DANGER("disabled") : "enabled"]."
/obj/machinery/gibber/emag_act(var/remaining_charges, var/mob/user)
emagged = !emagged
to_chat(user, SPAN_DANGER("You [emagged ? "disable" : "enable"] [src]'s safety guard."))
@@ -112,34 +149,39 @@
return
move_into_gibber(user, dropped)
/obj/machinery/gibber/proc/move_into_gibber(var/mob/user,var/mob/living/victim)
/**
* Moves the victim into the gibber. This can be triggered by a user trying to place the victim inside, or by
* being sucked in via the input plate.
*/
/obj/machinery/gibber/proc/move_into_gibber(var/mob/user, var/mob/victim, var/automatic = FALSE)
// All of these check for a user because if the machine is working autonomously, there's no one to send messages to in most cases we'd want to.
if(occupant)
to_chat(user, SPAN_DANGER("[src] is full, empty it first!"))
return
return FALSE
if(operating)
to_chat(user, SPAN_DANGER("[src] is locked and running, wait for it to finish."))
return
return FALSE
if(!(iscarbon(victim) || isanimal(victim)))
to_chat(user, SPAN_DANGER("This is not suitable for [src]!"))
return
return FALSE
if(ishuman(victim) && !emagged && !victim.isMonkey())
to_chat(user, SPAN_DANGER("[src]'s safety guard is engaged!"))
return
return FALSE
if(victim.abiotic(1))
to_chat(user, SPAN_DANGER("[victim] may not have abiotic items on."))
return
return FALSE
user.visible_message(SPAN_DANGER("[user] starts to put [victim] into [src]!"))
add_fingerprint(user)
if(!do_mob(user, victim, 30 SECONDS) || occupant || !victim.Adjacent(src) || !user.Adjacent(src) || !victim.Adjacent(user))
return
user.visible_message(SPAN_DANGER("[user] stuffs [victim] into [src]!"))
if(victim.client)
victim.client.perspective = EYE_PERSPECTIVE
victim.client.eye = src
@@ -171,7 +213,6 @@
update_icon()
return
/obj/machinery/gibber/proc/startgibbing(mob/user as mob)
if(operating)
return
@@ -219,12 +260,11 @@
spawn(gib_time)
operating = 0
operating = FALSE
occupant.gib()
occupant = null
playsound(loc, 'sound/effects/splat.ogg', 50, 1)
operating = 0
for (var/obj/thing in contents)
// Todo: unify limbs and internal organs
// There's a chance that the gibber will fail to destroy some evidence.
@@ -1,5 +1,3 @@
#define T_BOARD_MECHA(name) "" + "vehicle software " + "(" + (name) + ")"
/obj/item/circuitboard/exosystem
name = "vehicle software template"
icon = 'icons/obj/module.dmi'
@@ -9,26 +7,24 @@
var/list/contains_software = list()
/obj/item/circuitboard/exosystem/engineering
name = T_BOARD_MECHA("engineering systems")
name = T_BOARD_VEHICLE("engineering systems")
contains_software = list(MECH_SOFTWARE_ENGINEERING)
origin_tech = list(TECH_DATA = 1)
/obj/item/circuitboard/exosystem/utility
name = T_BOARD_MECHA("utility systems")
name = T_BOARD_VEHICLE("utility systems")
contains_software = list(MECH_SOFTWARE_UTILITY)
icon_state = "mcontroller"
origin_tech = list(TECH_DATA = 1)
/obj/item/circuitboard/exosystem/medical
name = T_BOARD_MECHA("medical systems")
name = T_BOARD_VEHICLE("medical systems")
contains_software = list(MECH_SOFTWARE_MEDICAL)
icon_state = "mcontroller"
origin_tech = list(TECH_DATA = 3,TECH_BIO = 2)
/obj/item/circuitboard/exosystem/weapons
name = T_BOARD_MECHA("ballistic weapon systems")
name = T_BOARD_VEHICLE("ballistic weapon systems")
contains_software = list(MECH_SOFTWARE_WEAPONS)
icon_state = "mainboard"
origin_tech = list(TECH_DATA = 3, TECH_COMBAT = 3)
#undef T_BOARD_MECHA
+21
View File
@@ -131,6 +131,11 @@
/obj/machinery/botany/extractor
name = "lysis-isolation centrifuge"
icon_state = "centrifuge"
component_types = list(
/obj/item/circuitboard/botany_extractor,
/obj/item/stock_parts/manipulator = 3,
/obj/item/stock_parts/scanning_module = 1
)
var/datum/seed/genetics // Currently scanned seed genetic structure.
var/degradation = 0 // Increments with each scan, stops allowing gene mods after a certain point.
@@ -263,6 +268,11 @@
name = "bioballistic delivery system"
icon_state = "traitgun"
disk_needs_genes = 1
component_types = list(
/obj/item/circuitboard/botany_editor,
/obj/item/stock_parts/manipulator = 3,
/obj/item/stock_parts/scanning_module = 1
)
/obj/machinery/botany/editor/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
@@ -330,3 +340,14 @@
usr.set_machine(src)
src.add_fingerprint(usr)
/obj/item/circuitboard/botany_extractor
name = T_BOARD("lysis-isolation centrifuge")
build_path = /obj/machinery/botany/extractor
origin_tech = list(TECH_DATA = 3)
/obj/item/circuitboard/botany_editor
name = T_BOARD("bioballistic delivery system")
build_path = /obj/machinery/botany/editor
origin_tech = list(TECH_DATA = 3)
+1 -1
View File
@@ -89,7 +89,7 @@ GLOBAL_LIST_INIT(minevendor_list, list(
shuttle = set_shuttle
/obj/item/circuitboard/machine/mining_equipment_vendor
name = "circuit board (Mining Equipment Vendor)"
name = T_BOARD("Mining Equipment Vendor")
build_path = /obj/machinery/mineral/equipment_vendor
origin_tech = list(TECH_DATA = 1, TECH_ENGINEERING = 1)
req_components = list( /obj/item/stock_parts/console_screen = 1,
+23 -12
View File
@@ -1,33 +1,46 @@
// At minimum every mob has a hear_say proc.
/**
* hear_say's return value determines whether or not the mob in question also receives a langchat image.
*/
/mob/proc/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol, var/font_size = null)
if(!istype(src, /mob/living/test) && cant_hear())
return
return FALSE
if(speaker && !istype(speaker, /mob/living/test) && (!speaker.client && istype(src,/mob/abstract/ghost/observer) && client.prefs.toggles & CHAT_GHOSTEARS && !(speaker in view(src))))
//Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE')
//Or someone snoring. So we make it where they won't hear it.
return
if((language && (language.flags & KNOWONLYHEAR)) && !say_understands(speaker, language))
return
return FALSE
//make sure the air can transmit speech - hearer's side
var/turf/T = get_turf(src)
var/vacuum_proof = ((language && (language.flags & PRESSUREPROOF)) || isghost(src))
var/speaker_name
if(ishuman(speaker))
var/mob/living/carbon/human/H = speaker
speaker_name = H.GetVoice()
if(T && !vacuum_proof) //Ghosts can hear even in vacuum.
var/datum/gas_mixture/environment = T.return_air()
var/pressure = (environment)? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1)
return
var/distance_to_speaker = get_dist(speaker, src)
if(pressure < SOUND_MINIMUM_PRESSURE && distance_to_speaker > 1)
// Yeah, this isn't quite realistic to be able to see if someone is talking through, say, an opaque mask, but for gameplay purposes it should help indicate that you're not bugged.
if(distance_to_speaker <= 4 && !italics)
to_chat(src, SPAN_NOTICE("[speaker_name] talks, but you're in a vacuum. Maybe if you were close enough for the sound to transmit through touch..."))
return FALSE
if (pressure < ONE_ATMOSPHERE*0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
italics = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
if((language && (language.flags & KNOWONLYHEAR)) && !say_understands(speaker, language))
return TRUE
if(!vr_mob && (sleeping || stat == UNCONSCIOUS))
hear_sleep(message)
return
return FALSE
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
if (language && (language.flags & NONVERBAL))
@@ -38,10 +51,6 @@
message = language ? language.scramble(message, languages) : stars(message)
var/accent_icon = speaker.get_accent_icon(language, src)
var/speaker_name = speaker.name
if(ishuman(speaker))
var/mob/living/carbon/human/H = speaker
speaker_name = H.GetVoice()
if(italics)
message = "<i>[message]</i>"
@@ -58,8 +67,10 @@
if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set
if(speaker == src)
to_chat(src, SPAN_WARNING("You cannot hear yourself speak!"))
return FALSE
else
to_chat(src, "<span class='name'>[speaker_name]</span>[alt_name] talks but you cannot hear them.")
return FALSE
else
if(language)
if(font_size)
@@ -106,10 +106,6 @@
qdel(extracted_slime)
update_icon()
#ifndef T_BOARD
#error T_BOARD macro is not defined but we need it!
#endif
/obj/item/circuitboard/slime_extractor
name = T_BOARD("slime extractor")
build_path = "/obj/machinery/slime_extractor"
+11 -2
View File
@@ -248,6 +248,13 @@ var/list/channel_to_radio_key = new
if(!verb)
verb = say_quote(message, speaking, is_singing, whisper)
var/is_shouting = FALSE
if(speaking)
for(var/verb_to_check in speaking.shout_verb)
if(verb_to_check == verb)
is_shouting = TRUE
continue
if(is_muzzled())
to_chat(src, SPAN_DANGER("You're muzzled and cannot speak!"))
return
@@ -357,8 +364,10 @@ var/list/channel_to_radio_key = new
var/list/langchat_styles = list()
if(istype(speaking, /datum/language/noise))
langchat_styles = list("emote", "langchat_small")
if(istype(speaking, /datum/language/noise))
langchat_styles = list("emote", "langchat_small")
if(whisper)
langchat_styles = list("langchat_italic")
if(is_shouting)
langchat_styles = list("langchat_yell")
langchat_speech(message, get_hearers_in_view(message_range, src), speaking, additional_styles = langchat_styles)
+4 -2
View File
@@ -3,5 +3,7 @@
desc = "An unknown location."
invisibility = 101
var/height = 1 ///< The number of Z-Levels in the map.
var/turf/edge_type ///< What the map edge should be formed with. (null = world.turf)
/// The number of Z-Levels in the map.
var/height = 1
/// What the map edge should be formed with. (null = world.turf)
var/turf/edge_type
+1 -1
View File
@@ -1,6 +1,6 @@
GLOBAL_LIST_EMPTY(connected_z_cache)
// If the height is more than 1, we mark all contained levels as connected.
/// If the height is more than 1, we mark all contained levels as connected.
/obj/effect/landmark/map_data/New(turf/loc, _height)
..()
if(!istype(loc)) // Using loc.z is safer when using the maploader and New.
+14 -7
View File
@@ -17,7 +17,7 @@
/obj/effect/hoist_hook
name = "hoist clamp"
desc = "A clamp used to lift people or things."
desc = "A clamp used to safely lift (or lower) people or things."
icon = 'icons/obj/hoists.dmi'
icon_state = "hoist_hook"
var/obj/structure/hoist/source_hoist
@@ -26,8 +26,9 @@
/obj/effect/hoist_hook/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
. += "To use the hook, click drag the object you want to it to attach it."
. += "To remove an object from the hook, click drag the hook to a nearby turf."
. += "Use this on yourself to deploy the hoist in the direction you're facing."
. += "To load something onto the hook, click-drag the object you want to it to attach it."
. += "To remove something from the hook, click-drag the hook to a nearby turf."
/obj/effect/hoist_hook/attack_hand(mob/living/user)
if (use_check_and_message(user, USE_DISALLOW_SILICONS))
@@ -89,7 +90,7 @@
user.visible_message(SPAN_NOTICE("[user] detaches \the [source_hoist.hoistee] from the hoist clamp."), SPAN_NOTICE("You detach \the [source_hoist.hoistee] from the hoist clamp."), SPAN_NOTICE("You hear something unclamp."))
source_hoist.release_hoistee()
// This will handle mobs unbuckling themselves.
/// This will handle mobs unbuckling themselves.
/obj/effect/hoist_hook/unbuckle()
. = ..()
if (. && !QDELETED(source_hoist))
@@ -111,8 +112,14 @@
/obj/structure/hoist/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
. += "To use the hook, click drag the object you want to it to attach it."
. += "To remove an object from the hook, click drag the hook to a nearby turf."
. += "To load something onto the hook, click-drag the object you want to it to attach it."
. += "Use an empty hand on the hoist to start the pulley lifting or lowering."
. += "To remove something from the hook, click-drag the hook to a nearby turf."
/obj/structure/hoist/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
if(broken)
. += "It looks broken, and the clamp has retracted back into the hoist. Seems like you'd have to re-deploy it to get it to work again."
/obj/structure/hoist/Initialize(mapload, ndir)
. = ..()
@@ -131,6 +138,7 @@
source_hoist = null
return ..()
/// Checks that the hoistee and the hook its supposed to be attached to are on the same z-level. If not, release the hoistee.
/obj/structure/hoist/proc/check_consistency()
if(hoistee && (hoistee.z != source_hook.z))
release_hoistee()
@@ -146,7 +154,6 @@
if(broken)
return
broken = TRUE
desc += " It looks broken, and the clamp has retracted back into the hoist. Seems like you'd have to re-deploy it to get it to work again."
if(hoistee)
release_hoistee()
QDEL_NULL(source_hook)
+7 -2
View File
@@ -1,15 +1,20 @@
/obj/item/ladder_mobile
name = "mobile ladder"
desc = "A lightweight deployable ladder, which you can use to move up or down. Or alternatively, you can bash some faces in."
desc = "A lightweight deployable ladder, which you can use to move up or down. Alternatively, you can bash some faces in; it'll hurt, a lot."
icon_state = "mobile_ladder"
item_state = "mobile_ladder"
icon = 'icons/obj/multiz_items.dmi'
contained_sprite = TRUE
throw_range = 3
force = 15
force = 18
w_class = WEIGHT_CLASS_BULKY
slot_flags = SLOT_BACK
/obj/item/ladder_mobile/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
. += "Use this on a solid floor (with open space above it) to place the ladder going up."
. += "Use this on an open space turf (with solid floor beneath it) to place the ladder going down."
/obj/item/ladder_mobile/proc/place_ladder(atom/A, mob/user)
if (isopenturf(A)) //Place into open space
+4 -2
View File
@@ -4,7 +4,8 @@
/obj/machinery/atmospherics/pipe/zpipe
icon = 'icons/atmos/pipes.dmi'
icon_state = "up"
var/ptype // What direction of pipe this is. Used for icons.
/// What direction of pipe this is. Used for icons.
var/ptype
name = "upwards pipe"
desc = "A pipe segment to connect upwards."
@@ -15,7 +16,8 @@
initialize_directions = SOUTH
var/minimum_temperature_difference = 300
var/thermal_conductivity = 0 //WALL_HEAT_TRANSFER_COEFFICIENT No
// WALL_HEAT_TRANSFER_COEFFICIENT
var/thermal_conductivity = 0
var/maximum_pressure = ATMOS_DEFAULT_MAX_PRESSURE
var/fatigue_pressure = ATMOS_DEFAULT_FATIGUE_PRESSURE
+2 -2
View File
@@ -14,7 +14,7 @@
req_access = list(ACCESS_ENGINE_EQUIP)
obj_flags = OBJ_FLAG_ROTATABLE | OBJ_FLAG_SIGNALER
var/id
/// uses powernet power, not APC power
/// Uses powernet power, not APC power.
use_power = POWER_USE_OFF
/// 30 kW laser. I guess that means 30 kJ per shot.
active_power_usage = 30000
@@ -30,7 +30,7 @@
var/shot_counter = 0
var/state = EMITTER_LOOSE
var/locked = FALSE
/// special emitters notify admins if something happens to them, to prevent grief
/// Special emitters notify admins if something happens to them, to prevent grief.
var/special_emitter = FALSE
var/_wifi_id
+109 -75
View File
@@ -7,33 +7,44 @@
icon = 'icons/obj/projectiles.dmi'
icon_state = "bullet"
density = FALSE
anchored = TRUE //There's a reason this is here, Mport. God fucking damn it -Agouri. Find&Fix by Pete. The reason this is here is to stop the curving of emitter shots.
anchored = TRUE
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
movement_type = FLYING
blocks_emissive = EMISSIVE_BLOCK_GENERIC
layer = MOB_LAYER
var/hitsound_wall = ""
unacidable = TRUE //should be `resistance_flags` but we don't have it yet
var/def_zone = "" //Aiming at
var/atom/movable/firer = null//Who shot it
var/datum/fired_from = null // the thing that the projectile was fired from (gun, turret, spell)
var/suppressed = FALSE //Attack message
/// Should be `resistance_flags` but we don't have it yet.
unacidable = TRUE
/// What body part/area we're aiming at.
var/def_zone = ""
/// Who shot it.
var/atom/movable/firer = null
/// The thing that the projectile was fired from (gun, turret, spell).
var/datum/fired_from = null
/// Attack message.
var/suppressed = FALSE
var/yo = null
var/xo = null
var/atom/original // the original target clicked
var/turf/starting // the projectile's starting turf
/// The original target clicked.
var/atom/original
/// The projectile's starting turf.
var/turf/starting
var/p_x = 16
var/p_y = 16 // the pixel location of the tile that the player clicked. Default is the center
/// The pixel location of the tile that the player clicked. Default is the center.
var/p_y = 16
//Fired processing vars
var/fired = FALSE //Have we been fired yet
var/paused = FALSE //for suspending the projectile midair
/// Have we been fired yet
var/fired = FALSE
/// For suspending the projectile midair
var/paused = FALSE
var/last_projectile_move = 0
var/last_process = 0
var/time_offset = 0
var/datum/point/vector/trajectory
var/trajectory_ignore_forcemove = FALSE //instructs forceMove to NOT reset our trajectory to the new location!
/// Instructs forceMove to NOT reset our trajectory to the new location!
var/trajectory_ignore_forcemove = FALSE
/// We already impacted these things, do not impact them again. Used to make sure we can pierce things we want to pierce. Lazylist, typecache style (object = TRUE) for performance.
var/list/impacted = list()
/// If TRUE, we can hit our firer.
@@ -55,16 +66,16 @@
*/
/// The "usual" flags of pass_flags is used in that can_hit_target ignores these unless they're specifically targeted/clicked on. This behavior entirely bypasses process_hit if triggered, rather than phasing which uses prehit_pierce() to check.
pass_flags = PASSTABLE|PASSRAILING
/// If FALSE, allow us to hit something directly targeted/clicked/whatnot even if we're able to phase through it
/// If FALSE, allow us to hit something directly targeted/clicked/whatnot even if we're able to phase through it.
var/phasing_ignore_direct_target = FALSE
/// Bitflag for things the projectile should just phase through entirely - No hitting unless direct target and [phasing_ignore_direct_target] is FALSE. Uses pass_flags flags.
var/projectile_phasing = NONE
/// Bitflag for things the projectile should hit, but pierce through without deleting itself. Defers to projectile_phasing. Uses pass_flags flags.
var/projectile_piercing = NONE
/// number of times we've pierced something. Incremented BEFORE bullet_act and on_hit proc!
/// Number of times we've pierced something. Incremented BEFORE bullet_act and on_hit proc!
var/pierces = 0
/// If objects are below this layer, we pass through them
/// If objects are below this layer, we pass through them.
var/hit_threshhold = PROJECTILE_HIT_THRESHHOLD_LAYER
/// During each fire of SSprojectiles, the number of deciseconds since the last fire of SSprojectiles
@@ -82,38 +93,45 @@
/// The current angle of the projectile. Initially null, so if the arg is missing from [/fire()], we can calculate it from firer and target as fallback.
var/Angle
var/original_angle = 0 //Angle at firing
var/nondirectional_sprite = FALSE //Set TRUE to prevent projectiles from having their sprites rotated based on firing angle
var/spread = 0 //amount (in degrees) of projectile spread
animate_movement = NO_STEPS //Use SLIDE_STEPS in conjunction with legacy
/// how many times we've ricochet'd so far (instance variable, not a stat)
/// Angle at firing.
var/original_angle = 0
/// Set TRUE to prevent projectiles from having their sprites rotated based on firing angle.
var/nondirectional_sprite = FALSE
/// Amount (in degrees) of projectile spread.
var/spread = 0
/// Use SLIDE_STEPS in conjunction with legacy.
animate_movement = NO_STEPS
/// How many times we've ricochet'd so far (instance variable, not a stat).
var/ricochets = 0
/// how many times we can ricochet max
/// How many times we can ricochet max.
var/ricochets_max = 0
/// how many times we have to ricochet min (unless we hit an atom we can ricochet off)
/// How many times we have to ricochet min (unless we hit an atom we can ricochet off).
var/min_ricochets = 0
/// 0-100 (or more, I guess), the base chance of ricocheting, before being modified by the atom we shoot and our chance decay
/// 0-100 (or more, I guess), the base chance of ricocheting, before being modified by the atom we shoot and our chance decay.
var/ricochet_chance = 0
/// 0-1 (or more, I guess) multiplier, the ricochet_chance is modified by multiplying this after each ricochet
/// 0-1 (or more, I guess) multiplier, the ricochet_chance is modified by multiplying this after each ricochet.
var/ricochet_decay_chance = 0.7
/// 0-1 (or more, I guess) multiplier, the projectile's damage is modified by multiplying this after each ricochet
/// 0-1 (or more, I guess) multiplier, the projectile's damage is modified by multiplying this after each ricochet.
var/ricochet_decay_damage = 0.7
/// On ricochet, if nonzero, we consider all mobs within this range of our projectile at the time of ricochet to home in on like Revolver Ocelot, as governed by ricochet_auto_aim_angle
/// On ricochet, if nonzero, we consider all mobs within this range of our projectile at the time of ricochet to home in on like Revolver Ocelot, as governed by ricochet_auto_aim_angle.
var/ricochet_auto_aim_range = 0
/// On ricochet, if ricochet_auto_aim_range is nonzero, we'll consider any mobs within this range of the normal angle of incidence to home in on, higher = more auto aim
/// On ricochet, if ricochet_auto_aim_range is nonzero, we'll consider any mobs within this range of the normal angle of incidence to home in on, higher = more auto aim.
var/ricochet_auto_aim_angle = 30
/// the angle of impact must be within this many degrees of the struck surface, set to 0 to allow any angle
/// The angle of impact must be within this many degrees of the struck surface, set to 0 to allow any angle.
var/ricochet_incidence_leeway = 40
/// Can our ricochet autoaim hit our firer?
var/ricochet_shoots_firer = TRUE
//Hitscan
var/hitscan = FALSE //Whether this is hitscan. If it is, speed is basically ignored.
var/list/beam_segments //assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation.
/// Whether this is hitscan. If it is, speed is basically ignored.
var/hitscan = FALSE
/// Assoc list of datum/point or datum/point/vector, start = end. Used for hitscan effect generation.
var/list/beam_segments
/// Last turf an angle was changed in for hitscan projectiles.
var/turf/last_angle_set_hitscan_store
var/datum/point/beam_index
var/turf/hitscan_last //last turf touched during hitscanning.
/// Last turf touched during hitscanning.
var/turf/hitscan_last
var/tracer_type
var/muzzle_type
var/impact_type
@@ -132,38 +150,47 @@
//Homing
var/homing = FALSE
var/atom/homing_target
var/homing_turn_speed = 10 //Angle per tick.
var/homing_inaccuracy_min = 0 //in pixels for these. offsets are set once when setting target.
/// Angle per tick.
var/homing_turn_speed = 10
/// In pixels for these. offsets are set once when setting target.
var/homing_inaccuracy_min = 0
var/homing_inaccuracy_max = 0
var/homing_offset_x = 0
var/homing_offset_y = 0
var/damage = 10
var/damage_type = DAMAGE_BRUTE //DAMAGE_BRUTE, DAMAGE_BURN, DAMAGE_TOXIN, DAMAGE_OXY, DAMAGE_CLONE, DAMAGE_PAIN are the only things that should be in here
/// DAMAGE_BRUTE, DAMAGE_BURN, DAMAGE_TOXIN, DAMAGE_OXY, DAMAGE_CLONE, DAMAGE_PAIN are the only things that should be in here.
var/damage_type = DAMAGE_BRUTE
var/range = 50 //This will de-increment every step. When 0, it will deletze the projectile.
var/decayedRange //stores original range
var/reflect_range_decrease = 5 //amount of original range that falls off when reflecting, so it doesn't go forever
/// This will de-increment every step. When 0, it will deletze the projectile.
var/range = 50
/// Stores original range.
var/decayedRange
/// Amount of original range that falls off when reflecting, so it doesn't go forever.
var/reflect_range_decrease = 5
var/impact_effect_type //what type of impact effect to show when hitting something
var/log_override = FALSE //is this type spammed enough to not log? (KAs)
/// What type of impact effect to show when hitting something.
var/impact_effect_type
/// Is this type spammed enough to not log? (KAs).
var/log_override = FALSE
/// If true, the projectile won't cause any logging. Used for hallucinations and shit.
var/do_not_log = FALSE
var/shrapnel_type //type of shrapnel the projectile leaves in its target.
/// Type of shrapnel the projectile leaves in its target.
var/shrapnel_type
///If TRUE, hit mobs, even if they are lying on the floor and are not our target within MAX_RANGE_HIT_PRONE_TARGETS tiles
/// If TRUE, hit mobs, even if they are lying on the floor and are not our target within MAX_RANGE_HIT_PRONE_TARGETS tiles.
var/hit_prone_targets = FALSE
///if TRUE, ignores the range of MAX_RANGE_HIT_PRONE_TARGETS tiles of hit_prone_targets
/// If TRUE, ignores the range of MAX_RANGE_HIT_PRONE_TARGETS tiles of hit_prone_targets.
var/ignore_range_hit_prone_targets = FALSE
///How much we want to drop damage per tile as it travels through the air
/// How much we want to drop damage per tile as it travels through the air.
var/damage_falloff_tile
///How much accuracy is lost for each tile travelled
/// How much accuracy is lost for each tile travelled.
var/accuracy_falloff = 7
///How much accuracy before falloff starts to matter. Formula is range - falloff * tiles travelled
/// How much accuracy before falloff starts to matter. Formula is range - falloff * tiles travelled.
var/accurate_range = 100
var/static/list/projectile_connections = list(COMSIG_ATOM_ENTERED = PROC_REF(on_entered))
/// If true directly targeted turfs can be hit
/// If TRUE, directly targeted turfs can be hit.
var/can_hit_turfs = FALSE
@@ -171,18 +198,21 @@
START AURORA SNOWFLAKE VARS SECTION
#########################################*/
var/ping_effect = "ping_b" //Effect displayed when a bullet hits a barricade. See atom/proc/bullet_ping.
/// Effect displayed when a bullet hits a barricade. See atom/proc/bullet_ping.
var/ping_effect = "ping_b"
///How accurate a bullet is *if it's hitting a mob* at getting the zone aimed at
/// How accurate a bullet is *if it's hitting a mob* at getting the zone aimed at.
var/accuracy = 0
//used for shooting at blank range, you shouldn't be able to miss
/// Used for shooting at blank range, you shouldn't be able to miss.
var/point_blank = FALSE
//Effects
/// Effects (bio and rad are also valid)
var/damage_flags = DAMAGE_FLAG_BULLET
var/check_armor = BULLET //Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb //Cael - bio and rad are also valid
var/list/impact_sounds //for different categories, IMPACT_MEAT etc
/// Defines what armor to use when it hits things. Must be set to bullet, laser, energy,or bomb
var/check_armor = BULLET
/// For different categories, IMPACT_MEAT etc
var/list/impact_sounds
var/stun = 0
var/weaken = 0
@@ -194,20 +224,24 @@
var/agony = 0
var/incinerate = 0
var/embed = 0 // whether or not the projectile can embed itself in the mob
var/embed_chance = 0 // a flat bonus to the % chance to embed
/// Whether or not the projectile can embed itself in the mob
var/embed = 0
/// A flat bonus to the % chance to embed
var/embed_chance = 0
//For Maim / Maiming.
var/maim_rate = 0 //Factor that the recipiant will be maimed by the projectile (NOT OUT OF 100%.)
/// For maiming. Factor that the recipiant will be maimed by the projectile (NOT OUT OF 100%.)
var/maim_rate = 0
var/reflected = FALSE
var/penetrating = 0 //If greater than zero, the projectile will pass through dense objects as specified by on_penetrate()
/// If greater than zero, the projectile will pass through dense objects as specified by on_penetrate()
var/penetrating = 0
/// For KAs, really.
var/aoe = 0
var/aoe = 0 //For KAs, really
var/anti_materiel_potential = 1 //how much the damage of this bullet is increased against mechs
/// How much the damage of this bullet is increased against mechs.
var/anti_materiel_potential = 1
/*########################################
END AURORA SNOWFLAKE VARS SECTION
@@ -339,7 +373,6 @@
return
Impact(A)
/**
* Called when the projectile hits something
* This can either be from it bumping something,
@@ -488,9 +521,10 @@
// 6. nothing
// (returns null)
//Returns true if the target atom is on our current turf and above the right layer
//If direct target is true it's the originally clicked target.
/**
* Returns true if the target atom is on our current turf and above the right layer
* If direct target is true it's the originally clicked target.
*/
/obj/projectile/proc/can_hit_target(atom/target, direct_target = FALSE, ignore_loc = FALSE, cross_failed = FALSE)
if(QDELETED(target) || impacted[target.weak_reference])
return FALSE
@@ -971,19 +1005,19 @@
if(!user.client)
CRASH("Can't make trajectory calculations without a target or click modifiers and a client.")
//Split screen-loc up into X+Pixel_X and Y+Pixel_Y
/// Split screen-loc up into X+Pixel_X and Y+Pixel_Y
var/list/screen_loc_params = splittext(LAZYACCESS(modifiers, SCREEN_LOC), ",")
//Split X+Pixel_X up into list(X, Pixel_X)
/// Split X+Pixel_X up into list(X, Pixel_X)
var/list/screen_loc_X = splittext(screen_loc_params[1],":")
//Split Y+Pixel_Y up into list(Y, Pixel_Y)
/// Split Y+Pixel_Y up into list(Y, Pixel_Y)
var/list/screen_loc_Y = splittext(screen_loc_params[2],":")
var/tx = (text2num(screen_loc_X[1]) - 1) * world.icon_size + text2num(screen_loc_X[2])
// We are here trying to lower our target location by the firing source's visual offset
// So visually things make a nice straight line while properly accounting for actual physical position
/// We are here trying to lower our target location by the firing source's visual offset
/// So visually things make a nice straight line while properly accounting for actual physical position
var/ty = (text2num(screen_loc_Y[1]) - 1) * world.icon_size + text2num(screen_loc_Y[2]) - source.pixel_z
//Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
/// Calculate the "resolution" of screen based on client's view and world's icon size. This will work if the user can view more tiles than average.
var/list/screenview = view_to_pixels(user.client.view)
var/ox = round(screenview[1] / 2) - user.client.pixel_x //"origin" x
@@ -1100,7 +1134,7 @@
AURORA SNOWFLAKE SECTION
##############################*/
//Checks if the projectile is eligible for embedding. Not that it necessarily will.
/// Checks if the projectile is eligible for embedding. Not that it necessarily will.
/obj/projectile/proc/can_embed()
//embed must be enabled and damage type must be brute
if(!embed || damage_type != DAMAGE_BRUTE)
@@ -1118,8 +1152,7 @@
return damage * anti_materiel_potential
return FALSE
//Because I don't want to rewrite half the world to use embed_data just yet,
//this is left as is, praise be the omnissiah
/// Because I don't want to rewrite half the world to use embed_data just yet, this is left as is, praise be the omnissiah
/obj/projectile/proc/do_embed(var/obj/item/organ/external/organ)
var/obj/item/SP = new shrapnel_type(organ)
SP.edge = TRUE
@@ -1137,7 +1170,8 @@
original = target
setAngle(get_projectile_angle(source, target))
/obj/projectile/proc/setAngle(new_angle) //wrapper for overrides.
/// wrapper for overrides.
/obj/projectile/proc/setAngle(new_angle)
Angle = new_angle
if(!nondirectional_sprite)
var/matrix/M = new
@@ -1161,7 +1195,7 @@
. += "Shrapnel Type: [shrapnel.name]<br>"
. += "Armor Penetration: [initial(armor_penetration)]%<br>"
//This is where the bullet bounces off.
/// This is where the bullet bounces off.
/atom/proc/bullet_ping(obj/projectile/P, var/pixel_x_offset, var/pixel_y_offset)
if(!P || !P.ping_effect)
return
+2 -1
View File
@@ -13,7 +13,7 @@
var/frequency = 1
hitscan = 1
invisibility = 101 //beam projectiles are invisible as they are rendered by the effect engine
color = COLOR_RED
// color = COLOR_RED
muzzle_type = /obj/effect/projectile/muzzle/laser
tracer_type = /obj/effect/projectile/tracer/laser
@@ -151,6 +151,7 @@
name = "emitter beam"
icon_state = "emitter"
damage = 0 // The actual damage is computed in /code/modules/power/singularity/emitter.dm
color = COLOR_SPRING_GREEN
muzzle_type = /obj/effect/projectile/muzzle/emitter
tracer_type = /obj/effect/projectile/tracer/emitter
@@ -39,16 +39,16 @@
icon_state = "pellets"
damage = 20
///Number of pellets that will be ejected from this bullet
/// Number of pellets that will be ejected from this bullet
var/pellets = 4
///The projectile will lose a pellet each time it travels this distance. Can be a non-integer.
/// The projectile will lose a pellet each time it travels this distance. Can be a non-integer.
var/range_step = 2
///Lower means the pellets spread more across body parts. If zero then this is considered a shrapnel explosion instead of a shrapnel cone
/// Lower means the pellets spread more across body parts. If zero then this is considered a shrapnel explosion instead of a shrapnel cone
var/base_spread = 90
///Higher means the pellets spread more across body parts with distance
/// Higher means the pellets spread more across body parts with distance
var/spread_step = 10
/obj/projectile/bullet/pellet/proc/get_pellets(var/distance)
@@ -69,7 +69,7 @@
var/total_pellets = get_pellets(distance)
var/spread = max(base_spread - (spread_step*distance), 0)
//shrapnel explosions miss prone mobs with a chance that increases with distance
// Shrapnel explosions miss prone mobs with a chance that increases with distance
var/prone_chance = 0
if(!base_spread)
prone_chance = max(spread_step*(distance - 2), 0)
@@ -125,7 +125,7 @@
agony = 50
embed = FALSE
var/balls = 4
///projectile will lose a fragment each time it travels this distance. Can be a non-integer.
/// Projectile will lose a fragment each time it travels this distance. Can be a non-integer.
var/range_step = 3
var/base_spread = 90
var/spread_step = 10
@@ -5,7 +5,7 @@
damage_type = DAMAGE_BURN
check_armor = ENERGY
//releases a burst of light on impact or after travelling a distance
/// Releases a burst of light on impact or after travelling a distance.
/obj/projectile/energy/flash
name = "chemical shell"
icon_state = "bullet"
@@ -36,7 +36,7 @@
single_spark(T)
new /obj/effect/smoke/illumination(T, brightness=max(flash_range*2, brightness), lifetime=light_duration)
//blinds people like the flash round, but can also be used for temporary illumination
/// blinds people like the flash round, but can also be used for temporary illumination
/obj/projectile/energy/flash/flare
damage = 10
flash_range = 1
+45 -26
View File
@@ -3,19 +3,25 @@
var/description = "A non-descript chemical."
var/taste_description = "old rotten bandaids"
var/list/species_taste_description
var/taste_mult = 1 //how this taste compares to others. Higher values means it is more noticable
/// How this taste compares to others. Higher values means it is more noticable.
var/taste_mult = 1
var/reagent_state = SOLID
var/metabolism = REM // This would be 0.2 normally
/// Default value is 0.2.
var/metabolism = REM
var/ingest_met = 0
var/touch_met = 0
var/breathe_met = 0
var/ingest_mul = 0.5
var/touch_mul = 0
var/breathe_mul = 0.75
var/overdose = 0 // Volume of a chemical required in the blood to meet overdose criteria.
var/od_minimum_dose = 5 // Metabolised dose of a chemical required to meet overdose criteria.
var/scannable = 0 // Shows up on health analyzers.
var/spectro_hidden = FALSE // doesn't show up on basic mass spectrometers, only shows on the advanced variant
/// Volume of a chemical required in the blood to meet overdose criteria.
var/overdose = 0
/// Metabolised dose of a chemical required to meet overdose criteria.
var/od_minimum_dose = 5
/// Shows up on health analyzers.
var/scannable = 0
/// Doesn't show up on basic mass spectrometers, only shows on the advanced variant
var/spectro_hidden = FALSE
var/affects_dead = 0
var/glass_icon_state = null
var/glass_name = null
@@ -28,22 +34,31 @@
var/condiment_center_of_mass = null
var/color = "#000000"
var/color_weight = 1
var/unaffected_species = IS_DIONA | IS_MACHINE // Species that aren't affected by this reagent. Does not prevent affect_touch.
var/metabolism_min = 0.01 //How much for the medicine to be present in the system to actually have an effect.
var/conflicting_reagent //Reagents that conflict with this medicine, and cause adverse effects when in the blood.
/// Species that aren't affected by this reagent. Does not prevent affect_touch.
var/unaffected_species = IS_DIONA | IS_MACHINE
/// How much for the medicine to be present in the system to actually have an effect.
var/metabolism_min = 0.01
/// Reagents that conflict with this medicine, and cause adverse effects when in the blood.
var/conflicting_reagent
var/default_temperature = T0C + 20 //This is its default spawning temperature, if none is provided.
var/specific_heat = -1 //The higher, the more difficult it is to change its temperature. 0 or lower values indicate that the specific heat has yet to be assigned.
var/fallback_specific_heat = -1 //Setting this value above 0 will set the specific heat to this value only if the system could not find an appropriate specific heat to assign using the recipe system.
//Never ever ever ever change this value for singleton/reagent. This should only be used for massive, yet specific things like drinks or food where it is infeasible to assign a specific heat value.
/// This is its default spawning temperature, if none is provided.
var/default_temperature = T0C + 20
/// The higher, the more difficult it is to change its temperature. 0 or lower values indicate that the specific heat has yet to be assigned.
var/specific_heat = -1
/// Setting this value above 0 will set the specific heat to this value only if the system could not find an appropriate specific heat to assign using the recipe system.
/// Never ever ever ever change this value for singleton/reagent. This should only be used for massive, yet specific things like drinks or food where it is infeasible to assign a specific heat value.
var/fallback_specific_heat = -1
var/germ_adjust = 0 // for makeshift bandages/disinfectant
var/carbonated = FALSE // if it's carbonated or not
/// For makeshift bandages/disinfectant
var/germ_adjust = 0
/// If it's carbonated or not.
var/carbonated = FALSE
/// Adds to the value of whatever container's holding it, value * units of reagents
var/value = 1
/singleton/reagent/proc/initialize_data(var/newdata, var/datum/reagents/holder) // Called when the reagent is created.
/// Called when the reagent is created.
/singleton/reagent/proc/initialize_data(var/newdata, var/datum/reagents/holder)
if(!isnull(newdata))
return newdata
@@ -57,7 +72,7 @@
else
H.vessel.reagent_data[/singleton/reagent/blood]["trace_chem"][type] = amount
// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing.
/// This doesn't apply to skin contact - this is for, e.g. extinguishers and sprays. The difference is that reagent is not directly on the mob's skin - it might just be on their clothing.
/singleton/reagent/proc/touch_mob(var/mob/living/M, var/amount, var/datum/reagents/holder)
return
@@ -78,7 +93,8 @@
var/OD_min = get_od_min_dose(M, location, holder)
return OD && (REAGENT_VOLUME(holder, type) > OD) && (LAZYACCESS(M.chem_doses, type) > OD_min) && (!location || (location != CHEM_TOUCH)) //OD based on volume in blood, but waits for a small amount of the drug to metabolise before kicking in.
/singleton/reagent/proc/on_mob_life(var/mob/living/carbon/M, var/alien, var/location, var/datum/reagents/holder) // Currently, on_mob_life is called on carbons. Any interaction with non-carbon mobs (lube) will need to be done in touch_mob.
/// Currently, on_mob_life is called on carbons. Any interaction with non-carbon mobs (lube) will need to be done in touch_mob.
/singleton/reagent/proc/on_mob_life(var/mob/living/carbon/M, var/alien, var/location, var/datum/reagents/holder)
if(!istype(M))
return
if(!affects_dead && M.stat == DEAD)
@@ -96,8 +112,9 @@
removed = M.get_metabolism(removed)
// ctual overdose threshold now = overdose + od_minimum_dose. ie. Synaptizine; 5u OD threshold + 1 unit min. metab'd dose = 6u actual OD threshold.
if(is_overdosing(M, location, holder))
overdose(M, alien, removed, LAZYACCESS(M.chem_doses, type)/get_overdose(M, location, holder), holder) //Actual overdose threshold now = overdose + od_minimum_dose. ie. Synaptizine; 5u OD threshold + 1 unit min. metab'd dose = 6u actual OD threshold.
overdose(M, alien, removed, LAZYACCESS(M.chem_doses, type)/get_overdose(M, location, holder), holder)
if(LAZYACCESS(M.chem_doses, type) <= 0)
initial_effect(M,alien, holder)
@@ -127,22 +144,22 @@
remove_self(removed, holder)
// Called when a beaker is thrown or something is hit with it, AND the beaker doesn't break.
/// Called when a beaker is thrown or something is hit with it, AND the beaker doesn't break.
/singleton/reagent/proc/apply_force(var/force, var/datum/reagents/holder)
return force
//Initial effect is called once when the reagent first starts affecting a mob.
/// Initial effect is called once when the reagent first starts affecting a mob.
/singleton/reagent/proc/initial_effect(var/mob/living/carbon/M, var/alien, var/datum/reagents/holder)
return
//Final effect is called once when the reagent finishes affecting a mob.
/// Final effect is called once when the reagent finishes affecting a mob.
/singleton/reagent/proc/final_effect(var/mob/living/carbon/M, var/datum/reagents/holder)
return
/singleton/reagent/proc/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder)
return
// if your chem directly affects other chems, use this to make sure all the chem_effects are applied before the standard chem affect_thing is run
/// If your chem directly affects other chems, use this to make sure all the chem_effects are applied before the standard chem affect_thing is run
/singleton/reagent/proc/affect_chem_effect(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder)
if(!istype(M))
return FALSE
@@ -167,13 +184,15 @@
if(breathe_mul)
affect_blood(M, alien, removed * breathe_mul, holder)
/singleton/reagent/proc/overdose(var/mob/living/carbon/M, var/alien, var/removed = 0, var/scale = 1, var/datum/reagents/holder) // Overdose effect. Doesn't happen instantly.
/// Overdose effect. Doesn't happen instantly.
/singleton/reagent/proc/overdose(var/mob/living/carbon/M, var/alien, var/removed = 0, var/scale = 1, var/datum/reagents/holder)
M.adjustToxLoss(REM)
/singleton/reagent/proc/mix_data(var/newdata, var/newamount, var/datum/reagents/holder) // You have a reagent with data, and new reagent with its own data get added, how do you deal with that?
/// You have a reagent with data, and new reagent with its own data get added, how do you deal with that?
/singleton/reagent/proc/mix_data(var/newdata, var/newamount, var/datum/reagents/holder)
return REAGENT_DATA(holder, type)
//Check to use when seeing if the person has the minimum dose of the reagent. Useful for stopping minimum transfer rate IV drips from applying chem effects
/// Check to use when seeing if the person has the minimum dose of the reagent. Useful for stopping minimum transfer rate IV drips from applying chem effects
/singleton/reagent/proc/check_min_dose(var/mob/living/carbon/M, var/min_dose = 1)
var/dose = REAGENT_VOLUME(M.reagents, type) >= min_dose
var/obj/item/organ/internal/stomach/S = M.internal_organs_by_name[BP_STOMACH]
@@ -12,7 +12,7 @@
/singleton/reagent/acetone/affect_blood(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder)
M.adjustToxLoss(removed * 3)
/singleton/reagent/acetone/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder) //I copied this wholesale from ethanol and could likely be converted into a shared proc. ~Techhead
/singleton/reagent/acetone/touch_obj(var/obj/O, var/amount, var/datum/reagents/holder)
if(istype(O, /obj/item/paper))
var/obj/item/paper/paperaffected = O
paperaffected.clearpaper()
@@ -783,6 +783,7 @@
/singleton/reagent/drugs/dionae_stimulant/diet
name = "diet Diesel"
description = "Diesel produced straight from the Narrows that has been made \"diet\" or decontaminated of radiation, making it safe for distribution around the Orion Spur."
fallback_specific_heat = 1
/singleton/reagent/drugs/dionae_stimulant/diet/initial_effect(mob/living/carbon/M, alien, datum/reagents/holder)
return
@@ -86,6 +86,7 @@
taste_description = "sharp tangy cheese"
reagent_state = SOLID
taste_mult = 3
fallback_specific_heat = 1
/singleton/reagent/nakarka/affect_ingest(var/mob/living/carbon/M, var/alien, var/removed, var/datum/reagents/holder)
..()
@@ -5,12 +5,15 @@
taste_mult = 4
reagent_state = SOLID
metabolism = REM * 2
var/nutriment_factor = 8 // Per removed in digest.
var/hydration_factor = 0 // Per removed in digest.
/// Per removed in digest.
var/nutriment_factor = 8
/// Per removed in digest.
var/hydration_factor = 0
var/blood_factor = 2
var/regen_factor = 0.8
var/injectable = 0
var/attrition_factor = -(REM * 4)/BASE_MAX_NUTRITION // Decreases attrition rate.
/// Decreases attrition rate.
var/attrition_factor = -(REM * 4)/BASE_MAX_NUTRITION
color = "#664330"
unaffected_species = IS_MACHINE
taste_description = "food"
@@ -59,6 +62,10 @@
M.add_chemical_effect(CE_BLOODRESTORE, blood_factor * removed)
M.intoxication -= min(M.intoxication,nutriment_factor*removed*0.05) //Nutrients can absorb alcohol.
/// Parent singleton. Provides fallback specific heat value to condiments unused in recipes.
/singleton/reagent/condiment
fallback_specific_heat = 1
//
//Lipozine?
//
@@ -193,18 +200,19 @@
if(amount >= 3)
T.wet_floor(WET_TYPE_LUBE,amount)
//Calculates a scaling factor for scalding damage, based on the temperature of the oil and creature's heat resistance
/// Calculates a scaling factor for scalding damage, based on the temperature of the oil and creature's heat resistance
/singleton/reagent/nutriment/triglyceride/oil/proc/heatdamage(var/mob/living/carbon/M, var/datum/reagents/holder)
var/threshold = 360//Human heatdamage threshold
/// Human heatdamage threshold.
var/threshold = 360
var/datum/species/S = M.get_species(1)
if (S && istype(S))
threshold = S.heat_level_1
//If temperature is too low to burn, return a factor of 0. no damage
// If temperature is too low to burn, return a factor of 0. no damage.
if (holder.get_temperature() < threshold)
return 0
//Step = degrees above heat level 1 for 1.0 multiplier
/// Step = degrees above heat level 1 for 1.0 multiplier.
var/step = 60
if (S && istype(S))
step = (S.heat_level_2 - S.heat_level_1)*1.5
@@ -1,9 +1,9 @@
/*
Coatings are used in cooking. Dipping food items in a reagent container with a coating in it
allows it to be covered in that, which will add a masked overlay to the sprite.
Coatings have both a raw and a cooked image. Raw coating is generally unhealthy
Generally coatings are intended for deep frying foods
/**
* Coatings are used in cooking. Dipping food items in a reagent container with a coating in it
* allows it to be covered in that, which will add a masked overlay to the sprite.
*
* Coatings have both a raw and a cooked image. Raw coating is generally unhealthy
* Generally coatings are intended for deep frying foodsGenerally coatings are intended for deep frying foods
*/
/singleton/reagent/nutriment/coating
nutriment_factor = 4 //Less dense than the food itself, but coatings still add extra calories
@@ -29,13 +29,13 @@
H.delayed_vomit()
. = ..()
/singleton/reagent/nutriment/coating/initialize_data(var/list/newdata, var/datum/reagents/holder) // Called when the reagent is created.
/// Called when the reagent is created.
/singleton/reagent/nutriment/coating/initialize_data(var/list/newdata, var/datum/reagents/holder)
var/list/data = ..()
LAZYSET(data, "cooked", istype(holder?.my_atom,/obj/item/reagent_containers/food/snacks))
if(data["cooked"])
name = cooked_name
return data
//Batter which is part of objects at compiletime spawns in a cooked state
/singleton/reagent/nutriment/coating/mix_data(var/list/newdata, var/newamount, var/datum/reagents/holder)
@@ -270,8 +270,8 @@
condiment_name = "hotsauce"
condiment_desc = "Hot sauce. It's in the name."
condiment_icon_state = "hotsauce"
var/agony_dose = 15 // Capsaicin required to proc agony. (3 to 5 chilis.)
/// Capsaicin required to proc agony. (3 to 5 chilis.)
var/agony_dose = 15
var/agony_amount = 1
var/discomfort_message = SPAN_DANGER("Your insides feel uncomfortably hot.")
var/slime_temp_adj = 10
@@ -2031,6 +2031,7 @@
metabolism = REM*0.0001
scannable = TRUE
taste_description = "pure death"
fallback_specific_heat = 1
/singleton/reagent/antibodies/affect_blood(mob/living/carbon/M, alien, removed, datum/reagents/holder)
. = ..()
@@ -2042,7 +2043,8 @@
Z.curing = TRUE
to_chat(M, SPAN_WARNING("Your [E.name] tightens, pulses, and squirms as \the [Z] fights back against the antibodies!"))
/singleton/reagent/caffeine // Copied from Hyperzine
/// Copied from Hyperzine
/singleton/reagent/caffeine
name = "Caffeine"
description = "Caffeine is a central nervous system stimulant found naturally in many plants. It's used as a mild cognitive enhancer to increase alertness, attentional performance, and improve cardiovascular health."
reagent_state = SOLID
@@ -2053,6 +2055,7 @@
taste_description = "bitter"
metabolism_min = REM * 0.025
breathe_met = REM * 0.15 * 0.5
fallback_specific_heat = 1
/singleton/reagent/caffeine/initial_effect(mob/living/carbon/M, alien, datum/reagents/holder)
. = ..()
@@ -4,19 +4,22 @@
icon = 'icons/obj/monitors.dmi'
icon_state = "auth_off"
obj_flags = OBJ_FLAG_MOVES_UNSUPPORTED
var/active = 0 //This gets set to 1 on all devices except the one where the initial request was made.
/// This gets set to TRUE on all devices except the one where the initial request was made.
var/active = FALSE
var/event = ""
var/screen = 1
var/confirmed = 0 //This variable is set by the device that confirms the request.
var/confirm_delay = 20 //(2 seconds)
var/busy = 0 //Busy when waiting for authentication or an event request has been sent from this device.
/// This variable is set by the device that confirms the request.
var/confirmed = FALSE
var/confirm_delay = 2 SECONDS
/// Busy when waiting for authentication, or an event request has been sent from this device.
var/busy = FALSE
var/obj/machinery/keycard_auth/event_source
var/mob/event_triggered_by
var/mob/event_confirmed_by
var/recorded_message = ""
//1 = select event
//2 = authenticate
anchored = 1.0
anchored = TRUE
idle_power_usage = 2
active_power_usage = 6
power_channel = AREA_USAGE_ENVIRON
@@ -40,7 +43,7 @@
/obj/machinery/keycard_auth/attackby(obj/item/attacking_item, mob/user)
if(stat & (NOPOWER|BROKEN))
to_chat(user, "This device is not powered.")
return
return FALSE
if(istype(attacking_item, /obj/item/card/id))
var/obj/item/card/id/ID = attacking_item
if(ACCESS_KEYCARD_AUTH in ID.access)
@@ -63,10 +66,10 @@
to_chat(user, "This device is not powered.")
return
if(!user.IsAdvancedToolUser())
return 0
return FALSE
if(busy)
to_chat(user, "This device is busy.")
return
return FALSE
user.set_machine(src)
@@ -111,10 +114,10 @@
return
/obj/machinery/keycard_auth/proc/reset()
active = 0
active = FALSE
event = ""
screen = 1
confirmed = 0
confirmed = FALSE
event_source = null
icon_state = "auth_off"
event_triggered_by = null
@@ -147,7 +150,7 @@
sleep(confirm_delay)
if(confirmed)
confirmed = 0
confirmed = FALSE
trigger_event(event, recorded_message, user)
log_game("[key_name(event_triggered_by)] triggered and [key_name(event_confirmed_by)] confirmed event [event]")
message_admins("[key_name_admin(event_triggered_by)] triggered and [key_name_admin(event_confirmed_by)] confirmed event [event]", 1)
@@ -157,16 +160,16 @@
if(stat & (BROKEN|NOPOWER))
return
event_source = source
busy = 1
active = 1
busy = TRUE
active = TRUE
icon_state = "auth_on"
sleep(confirm_delay)
event_source = null
icon_state = "auth_off"
active = 0
busy = 0
active = FALSE
busy = FALSE
/obj/machinery/keycard_auth/proc/trigger_event(var/event, var/distress_message, var/mob/user)
switch(event)
@@ -196,12 +199,12 @@
/obj/machinery/keycard_auth/proc/is_ert_blocked()
if(GLOB.config.ert_admin_call_only)
return 1
return TRUE
if(SSticker.mode.ert_disabled)
SSticker.mode.announce_ert_disabled()
return 1
return TRUE
else
return 0
return FALSE
GLOBAL_VAR_INIT(maint_all_access, FALSE)
@@ -215,7 +218,7 @@ GLOBAL_VAR_INIT(maint_all_access, FALSE)
/obj/machinery/door/airlock/allowed(mob/M)
if(locked)
return 0
return FALSE
var/obj/item/I = M.GetIdCard()
if(!I)
@@ -224,7 +227,7 @@ GLOBAL_VAR_INIT(maint_all_access, FALSE)
var/maint_sec_access = ((GLOB.security_level > SEC_LEVEL_GREEN) && has_access(ACCESS_SECURITY, accesses = A))
var/exceptional_circumstances = GLOB.maint_all_access || maint_sec_access
if(exceptional_circumstances && src.check_access_list(list(ACCESS_MAINT_TUNNELS)))
return 1
return TRUE
if(access_by_level || req_one_access_by_level)
var/sec_level = get_security_level()
if(sec_level in (req_one_access_by_level ? req_one_access_by_level : access_by_level))