diff --git a/aurorastation.dme b/aurorastation.dme index 4f82d0591a7..053eb9446e7 100644 --- a/aurorastation.dme +++ b/aurorastation.dme @@ -570,6 +570,7 @@ #include "code\game\area\ai_monitored.dm" #include "code\game\area\area_power.dm" #include "code\game\area\areas.dm" +#include "code\game\atom\_atom.dm" #include "code\game\atom\atoms_initializing_EXPENSIVE.dm" #include "code\game\dna\dna2.dm" #include "code\game\dna\dna2_domutcheck.dm" diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm index d099e721759..b75c241ed24 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm @@ -7,3 +7,12 @@ #define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZE "atom_init_success" //from SSatoms InitAtom - Only if the atom was not deleted or failed initialization and has a loc #define COMSIG_ATOM_AFTER_SUCCESSFUL_INITIALIZED_ON "atom_init_success_on" +///from base of atom/Entered(): (atom/movable/arrived, atom/old_loc, list/atom/old_locs) +#define COMSIG_ATOM_ENTERED "atom_entered" +/// Sent from the atom that just Entered src. From base of atom/Entered(): (/atom/destination, atom/old_loc, list/atom/old_locs) +#define COMSIG_ATOM_ENTERING "atom_entering" +///from base of atom/Exit(): (/atom/movable/leaving, direction) +#define COMSIG_ATOM_EXIT "atom_exit" + #define COMPONENT_ATOM_BLOCK_EXIT (1<<0) +///from base of atom/Exited(): (atom/movable/gone, direction) +#define COMSIG_ATOM_EXITED "atom_exited" diff --git a/code/datums/observation/entered.dm b/code/datums/observation/entered.dm index cbb08c2a219..6801a9d8f7c 100644 --- a/code/datums/observation/entered.dm +++ b/code/datums/observation/entered.dm @@ -14,11 +14,3 @@ GLOBAL_DATUM_INIT(entered_event, /singleton/observ/entered, new) /singleton/observ/entered name = "Entered" expected_type = /atom - -/******************* -* Entered Handling * -*******************/ - -/atom/Entered(atom/movable/enterer, atom/old_loc) - ..() - GLOB.entered_event.raise_event(src, enterer, old_loc) diff --git a/code/datums/observation/exited.dm b/code/datums/observation/exited.dm index d5dc95224a6..fd080d44be4 100644 --- a/code/datums/observation/exited.dm +++ b/code/datums/observation/exited.dm @@ -14,11 +14,3 @@ GLOBAL_DATUM_INIT(exited_event, /singleton/observ/exited, new) /singleton/observ/exited name = "Exited" expected_type = /atom - -/****************** -* Exited Handling * -******************/ - -/atom/Exited(atom/movable/exitee, atom/new_loc) - . = ..() - GLOB.exited_event.raise_event(src, exitee, new_loc) diff --git a/code/datums/observation/moved.dm b/code/datums/observation/moved.dm index f9aa6554bec..3c9586c95a1 100644 --- a/code/datums/observation/moved.dm +++ b/code/datums/observation/moved.dm @@ -44,10 +44,6 @@ GLOBAL_DATUM_INIT(moved_event, /singleton/observ/moved, new) /atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc) GLOB.moved_event.raise_event(src, old_loc, new_loc) -/atom/Entered(var/atom/movable/am, atom/old_loc) - ..() - GLOB.moved_event.raise_event(am, old_loc, am.loc) - /atom/movable/Entered(var/atom/movable/am, atom/old_loc) ..() if(GLOB.moved_event.has_listeners(am) && !GLOB.moved_event.is_listening(src, am)) diff --git a/code/game/area/area_power.dm b/code/game/area/area_power.dm index 09fc1622a00..1209178c759 100644 --- a/code/game/area/area_power.dm +++ b/code/game/area/area_power.dm @@ -43,7 +43,11 @@ oneoff_light = 0 oneoff_environ = 0 -// Don't call this unless you know what you're doing. See use_power_oneoff below. +/** + * Don't call this unless you know what you're doing + * + * See use_power_oneoff below + */ /area/proc/use_power(var/amount, var/chan) switch(chan) if(EQUIP) diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm new file mode 100644 index 00000000000..aeb942e4e46 --- /dev/null +++ b/code/game/atom/_atom.dm @@ -0,0 +1,46 @@ +/** + * The base type for nearly all physical objects in SS13 + + * Lots and lots of functionality lives here, although in general we are striving to move + * as much as possible to the components/elements system + */ + +/** + * An atom has entered this atom's contents + * + * Default behaviour is to send the [COMSIG_ATOM_ENTERED] + * + * Aurora note: old_locs is not populated currently, and will always be null + */ +/atom/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) + SEND_SIGNAL(src, COMSIG_ATOM_ENTERED, arrived, old_loc, old_locs) + SEND_SIGNAL(arrived, COMSIG_ATOM_ENTERING, src, old_loc, old_locs) + + //Observables event, Aurora snowflake code + GLOB.entered_event.raise_event(src, arrived, old_loc) + GLOB.moved_event.raise_event(arrived, old_loc, arrived.loc) + +/** + * An atom is attempting to exit this atom's contents + * + * Default behaviour is to send the [COMSIG_ATOM_EXIT] + */ +/atom/Exit(atom/movable/leaving, direction) + // Don't call `..()` here, otherwise `Uncross()` gets called. + // See the doc comment on `Uncross()` to learn why this is bad. + + if(SEND_SIGNAL(src, COMSIG_ATOM_EXIT, leaving, direction) & COMPONENT_ATOM_BLOCK_EXIT) + return FALSE + + //Observables event, Aurora snowflake code + GLOB.exited_event.raise_event(src, leaving, get_step_towards(src, direction)) + + return TRUE + +/** + * An atom has exited this atom's contents + * + * Default behaviour is to send the [COMSIG_ATOM_EXITED] + */ +/atom/Exited(atom/movable/gone, direction) + SEND_SIGNAL(src, COMSIG_ATOM_EXITED, gone, direction) diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index d9f2a118d11..9ee5c60d319 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -4,7 +4,6 @@ desc_info = "Click your target with Grab intent, then click on the table with an empty hand, to place them on it." icon = 'icons/obj/surgery.dmi' icon_state = "table2-idle" - var/modify_state = "table2" density = TRUE anchored = TRUE use_power = POWER_USE_IDLE @@ -15,39 +14,110 @@ /obj/item/stock_parts/scanning_module = 1 ) - var/mob/living/carbon/human/occupant = null + ///The base icon state that will be modified + var/modify_state = "table2" + + ///The person occupying the table, a weakref to a `/mob/living/carbon/human` + var/datum/weakref/occupant = null + + ///If the table is currently suppressing, aka active var/suppressing = FALSE + ///The connected surgery computer var/obj/machinery/computer/operating/computer = null - var/list/allowed_species = list( - SPECIES_HUMAN, - SPECIES_HUMAN_OFFWORLD, - SPECIES_SKRELL, - SPECIES_SKRELL_AXIORI, - SPECIES_UNATHI, - SPECIES_TAJARA, - SPECIES_TAJARA_MSAI, - SPECIES_TAJARA_ZHAN, - SPECIES_VAURCA_WORKER, - SPECIES_VAURCA_WARRIOR, - SPECIES_VAURCA_BREEDER, - SPECIES_VAURCA_BULWARK, - SPECIES_DIONA, - SPECIES_DIONA_COEUS, - SPECIES_MONKEY - ) /obj/machinery/optable/Initialize() - . = ..() + ..() + LAZYADD(can_buckle, /mob/living) buckle_delay = 30 - for(dir in GLOB.cardinal) - computer = locate(/obj/machinery/computer/operating, get_step(src, dir)) - if(computer) - computer.table = src + + RegisterSignal(loc, COMSIG_ATOM_ENTERED, PROC_REF(mark_patient)) + RegisterSignal(loc, COMSIG_ATOM_EXITED, PROC_REF(unmark_patient)) + + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/optable/LateInitialize() + . = ..() + + //Search for an operating computer and ask it to hook us up + for(var/obj/machinery/computer/operating/candidate_computer in orange(src, 1)) + if(candidate_computer.hook_table(src)) break +/obj/machinery/optable/Destroy() + STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + UnregisterSignal(loc, COMSIG_ATOM_ENTERED) + UnregisterSignal(loc, COMSIG_ATOM_EXITED) + + //If we have a computer, ask it to unhook us, clear the reference anyways just to be sure + if(computer) + computer.unhook_table(src) + computer = null + + //If there's an occupant, ensure to release the view before dropping the weakref + var/occupant_resolved = occupant?.resolve() + if(occupant_resolved) + release_view(occupant_resolved) + occupant = null + + . = ..() + +/// Any mob that enters our tile will awaken our processing as it's a potential patient +/obj/machinery/optable/proc/mark_patient(datum/source, mob/living/carbon/potential_patient) + SIGNAL_HANDLER + if(!istype(potential_patient)) + return + START_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + refresh_icon_state() + +/// Unmark the potential patient +/obj/machinery/optable/proc/unmark_patient(datum/source, mob/living/carbon/potential_patient) + SIGNAL_HANDLER + if(!istype(potential_patient)) + return + + //Stop processing only if it's not the occupant, or the occupant doesn't exist + var/occupant_resolved = occupant?.resolve() + if(isnull(occupant_resolved) || potential_patient == occupant_resolved) + STOP_PROCESSING_MACHINE(src, MACHINERY_PROCESS_SELF) + + //If it was the occupant, clear the var and give him back the view, and turn off the suppressor + if(potential_patient == occupant_resolved) + suppressing = FALSE + occupant = null //Null the weakref + release_view(potential_patient) + + //Reprocess the icon state at the end + refresh_icon_state() + +/obj/machinery/optable/process(seconds_per_tick) + //We just call the check_occupant for all the processing + check_occupant(seconds_per_tick) + +/** + * Acquires the view of the patient so that it's locked on the table, instead of eg. remote viewing a camera + */ +/obj/machinery/optable/proc/acquire_view(mob/living/carbon/patient) + //No point if there's no client + if(!patient.client) + return + + //Perspective according to the eye + patient.client.perspective = EYE_PERSPECTIVE + patient.client.eye = src + +/** + * Releases the view of the patient back to the mob + */ +/obj/machinery/optable/proc/release_view(mob/living/carbon/patient) + //No point if there's no client + if(!patient.client) + return + + patient.reset_view(null) + /obj/machinery/optable/examine(var/mob/user) . = ..() to_chat(user, SPAN_NOTICE("The neural suppressors are switched [suppressing ? "on" : "off"].")) @@ -73,18 +143,19 @@ qdel(src) return - if(!occupant) + var/mob/living/carbon/human/occupant_resolved = occupant?.resolve() + if(!occupant_resolved) to_chat(user, SPAN_WARNING("There is nobody on \the [src]. It would be pointless to turn the suppressor on.")) return TRUE if((user.a_intent != I_HELP) && buckled) user_unbuckle(user) return - if(user != occupant && !use_check_and_message(user)) // Skip checks if you're doing it to yourself or turning it off, this is an anti-griefing mechanic more than anything. + if(user != occupant_resolved && !use_check_and_message(user)) // Skip checks if you're doing it to yourself or turning it off, this is an anti-griefing mechanic more than anything. user.visible_message(SPAN_WARNING("\The [user] begins switching [suppressing ? "off" : "on"] \the [src]'s neural suppressor.")) if(!do_after(user, 3 SECONDS, src, DO_UNIQUE)) return - if(!occupant) + if(!occupant_resolved) to_chat(user, SPAN_WARNING("There is nobody on \the [src]. It would be pointless to turn the suppressor on.")) suppressing = !suppressing @@ -102,87 +173,145 @@ user.drop_from_inventory(O,get_turf(src)) ..() -/obj/machinery/optable/proc/check_occupant() - if(!occupant || !occupant.lying || occupant.loc != loc) - suppressing = FALSE - occupant = null - var/mob/living/carbon/human/H = locate() in loc - if(istype(H)) - if(H.lying) - icon_state = H.pulse() ? "[modify_state]-active" : "[modify_state]-idle" - occupant = H - if(occupant && !occupant.isSynthetic()) - if(suppressing && occupant.sleeping < 7) - occupant.Sleeping(7 - occupant.sleeping) - occupant.willfully_sleeping = FALSE - if(occupant.eye_blurry < 7) - occupant.eye_blurry = (7 - occupant.eye_blurry) - icon_state = occupant.pulse() ? "[modify_state]-active" : "[modify_state]-idle" - if(occupant.stat == DEAD || occupant.is_asystole() || occupant.status_flags & FAKEDEATH) - icon_state = "[modify_state]-critical" - return TRUE - icon_state = "[modify_state]-idle" - return FALSE +/** + * Refreshes the icon state based on the table status + */ +/obj/machinery/optable/proc/refresh_icon_state() + SHOULD_NOT_SLEEP(TRUE) -/obj/machinery/optable/process() - check_occupant() + var/mob/living/carbon/human/human_occupant = occupant?.resolve() -/obj/machinery/optable/proc/take_occupant(mob/living/carbon/C, mob/living/carbon/user) - if(C == user) - user.visible_message("\The [user] climbs on \the [src].", "You climb on \the [src].") - else - visible_message(SPAN_NOTICE("\The [C] has been laid on \the [src] by \the [user].")) - if(C.client) - C.client.perspective = EYE_PERSPECTIVE - C.client.eye = src - C.resting = TRUE - C.forceMove(loc) - add_fingerprint(user) - if(ishuman(C)) - var/mob/living/carbon/human/H = C - occupant = H - icon_state = H.pulse() ? "[modify_state]-active" : "[modify_state]-idle" - if(H.stat == DEAD || H.is_asystole() || H.status_flags & FAKEDEATH) + if(istype(human_occupant) && human_occupant.lying && !(human_occupant.isSynthetic())) + //If there's a bad condition, set the critical table icon + if(human_occupant.stat == DEAD || human_occupant.is_asystole() || (human_occupant.status_flags & FAKEDEATH) || !human_occupant.pulse()) icon_state = "[modify_state]-critical" + //Otherwise, as far as we can tell, the patient is alive; set the active table icon + else + icon_state = "[modify_state]-active" + + //Noone on the table or a synthetic, idle status else icon_state = "[modify_state]-idle" -/obj/machinery/optable/MouseDrop_T(mob/target, mob/user) - var/mob/living/M = user - if(user.stat || user.restrained() || !iscarbon(target)) + +/obj/machinery/optable/proc/check_occupant(seconds_per_tick) + SHOULD_NOT_SLEEP(TRUE) + + refresh_icon_state() + var/mob/living/carbon/human/occupant_resolved = occupant?.resolve() + + //If the occupant is not set + if(!occupant_resolved) + //Reset suppression + suppressing = FALSE + + //Try to find a patient, if you have one, set it as occupant + //does not mean it's suppressed, just that it's occupying the table + var/mob/living/carbon/human/new_occupant = locate() in loc + if(istype(new_occupant)) + if(new_occupant.lying) + //Set the occupant weakref and get his view + occupant = WEAKREF(new_occupant) + acquire_view(new_occupant) + + //We have a patient, and it's not synthetic + else if(!occupant_resolved.isSynthetic()) + //If the table is on and suppressing + if(suppressing) + if(stat & NOPOWER) + return FALSE + + src.use_power_oneoff(2 KILOWATTS) + + //Set it to unwillful sleep + occupant_resolved.Sleeping(3.5*seconds_per_tick) + occupant_resolved.willfully_sleeping = FALSE + + //Blur the vision + occupant_resolved.eye_blurry = max((3.5*seconds_per_tick), occupant_resolved.eye_blurry) + + return TRUE + + return FALSE + +/** + * To handle the 30 snowflake ways to get a mob on the table + * + * * patient - The (will be) occupant + * * giver - The person that is occupant the `patient` on the table + * + * Returns `TRUE` if the patient was taken, `FALSE` otherwise + */ +/obj/machinery/optable/proc/take_occupant(mob/living/carbon/patient, mob/living/carbon/giver) + SHOULD_NOT_SLEEP(TRUE) + + //No point if there's no patient + if(!istype(patient)) + return FALSE + + //Someone is already on the table + var/mob/living/carbon/human/occupant_resolved = occupant?.resolve() + if(occupant_resolved) + return FALSE + + if(patient == giver) //Putting yourself on the table + giver.visible_message("\The [giver] climbs on \the [src].", "You climb on \the [src].") + else //Putting someone else on the table, or noone + visible_message(SPAN_NOTICE("\The [patient] has been laid on \the [src] by \the [giver].")) + + //Add the fingerprints and fibers of both the giver and the patient + add_fingerprint(giver) + add_fibers(giver) + add_fingerprint(patient) + add_fibers(patient) + + patient.resting = TRUE + patient.forceMove(loc) + + return TRUE + +/obj/machinery/optable/MouseDrop_T(atom/dropping, mob/user) + var/mob/living/carbon/patient = dropping + //No point if it's not a possible patient + if(!istype(patient)) return - if(istype(M) && (get_turf(target) != get_turf(src))) - var/mob/living/L = target - var/bucklestatus = L.bucklecheck(user) + + //If the user is not able, stop + if(user.stat || user.restrained()) + return + + //It's already occupied, spessbro + var/mob/living/carbon/human/occupant_resolved = occupant?.resolve() + if(occupant_resolved) + to_chat(usr, SPAN_NOTICE(SPAN_BOLD("\The [src] is already occupied!"))) + return + + if((get_turf(patient) != get_turf(src))) + var/bucklestatus = patient.bucklecheck(user) if(!bucklestatus) return - if(L == user) + if(patient == user) user.visible_message(SPAN_NOTICE("\The [user] starts climbing onto \the [src]."), SPAN_NOTICE("You start climbing onto \the [src]."), range = 3) else - user.visible_message(SPAN_NOTICE("\The [user] starts putting [L] onto \the [src]."), SPAN_NOTICE("You start putting \the [L] onto \the [src]."), range = 3) - if(do_mob(user, L, 10, needhand = FALSE)) + user.visible_message(SPAN_NOTICE("\The [user] starts putting \the [patient] onto \the [src]."), SPAN_NOTICE("You start putting \the [patient] onto \the [src]."), range = 3) + + //Move the patient on the table after a short delay and buckle him + if(do_mob(user, patient, 1 SECOND, needhand = FALSE)) + //If he's already buckled to something, unbuckle him first if(bucklestatus == 2) - var/obj/structure/LB = L.buckled_to + var/obj/structure/LB = patient.buckled_to LB.user_unbuckle(user) - take_occupant(target,user) + take_occupant(patient, user) else return ..() -/obj/machinery/optable/verb/climb_on() - set name = "Climb On Table" - set category = "Object" - set src in oview(1) - - if(usr.stat || !ishuman(usr) || usr.restrained() ) - return - - take_occupant(usr,usr) - /obj/machinery/optable/attackby(obj/item/W, mob/living/carbon/user) if(istype(W, /obj/item/grab)) var/obj/item/grab/G = W - if(occupant) + + var/mob/living/carbon/human/occupant_resolved = occupant?.resolve() + if(occupant_resolved) to_chat(usr, SPAN_NOTICE(SPAN_BOLD("\The [src] is already occupied!"))) return TRUE @@ -205,21 +334,3 @@ return TRUE if(default_part_replacement(user, W)) return TRUE - -/obj/machinery/optable/proc/check_table(mob/living/carbon/patient) - check_occupant() - if(occupant?.lying && get_turf(occupant) == get_turf(src)) - to_chat(usr, SPAN_WARNING("\The [src] is already occupied!")) - return FALSE - if(patient.buckled_to) - to_chat(usr, SPAN_NOTICE("Unbuckle \the [patient] first!")) - return FALSE - return TRUE - -/obj/machinery/optable/proc/check_species() - if (!occupant || !ishuman(occupant)) - return TRUE - var/mob/living/carbon/human/O = occupant - if (!O) - return TRUE - return !(O.get_species() in allowed_species) diff --git a/code/game/machinery/body_scanner.dm b/code/game/machinery/body_scanner.dm index 175af6ccc9d..7a24ddfc920 100644 --- a/code/game/machinery/body_scanner.dm +++ b/code/game/machinery/body_scanner.dm @@ -886,7 +886,12 @@ /obj/machinery/body_scanconsole/embedded/get_occupant() if(monitor_console?.table) - return monitor_console.table.occupant + + if(istype(monitor_console.table.occupant, /datum/weakref)) + return monitor_console.table.occupant.resolve() + else + return monitor_console.table.occupant + return null // if our primer has a scan target, that means it was validated by a bodyscanner diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index 5c4ae53fe0f..697a4d59010 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -10,24 +10,79 @@ light_color = LIGHT_COLOR_BLUE circuit = /obj/item/circuitboard/operating + ///The operating table we are hooked into var/obj/machinery/optable/table + + ///The paper with the scan of the patient var/obj/item/paper/medscan/primer + var/obj/machinery/body_scanconsole/embedded/embedded_scanner /obj/machinery/computer/operating/Initialize() - . = ..() + ..() + embedded_scanner = new /obj/machinery/body_scanconsole/embedded(src, 0, TRUE, TRUE) - for(var/obj/machinery/optable/T in orange(1,src)) - table = T - if (table) - table.computer = src + + return INITIALIZE_HINT_LATELOAD + +/obj/machinery/computer/operating/LateInitialize() + . = ..() + + for(var/obj/machinery/optable/T in orange(1, src)) + var/successfully_hooked = hook_table(T) + if(successfully_hooked) break /obj/machinery/computer/operating/Destroy() QDEL_NULL(embedded_scanner) QDEL_NULL(primer) + + //Clear the operating table + if(table) + unhook_table(table) + + . = ..() + +/** + * Used to connect (hook) the computer to the operating table + * + * Returns `TRUE` on successful hook, `FALSE` otherwise + * + * * table_to_hook - An `/obj/machinery/optable` to hook to + */ +/obj/machinery/computer/operating/proc/hook_table(obj/machinery/optable/table_to_hook) + if(table) + return FALSE + + if(QDELETED(table_to_hook)) + crash_with("Trying to hook a QDELETED optable!") + return FALSE + + if(!istype(table_to_hook)) + crash_with("Trying to hook a table that is not of the correct type!") + return FALSE + + table = table_to_hook + table.computer = src + + return TRUE + +/** + * Used to disconnect (unhook) the computer to the operating table + * + * Returns `TRUE` on successful unhook, `FALSE` otherwise + * + * * table_to_unhook - An `/obj/machinery/optable` to hook to + */ +/obj/machinery/computer/operating/proc/unhook_table(obj/machinery/optable/table_to_unhook) + if(table_to_unhook != table) + crash_with("Trying to unhook a table that is not hooked!") + return FALSE + + table.computer = null table = null - return ..() + + return TRUE /obj/machinery/computer/operating/attackby(obj/item/item, mob/user) if(istype(item, /obj/item/paper/medscan)) diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index 30613523ce5..90a61c3089f 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -115,7 +115,10 @@ Class Procs: var/interact_offline = 0 // Can the machine be interacted with while de-powered. var/printing = 0 // Is this machine currently printing anything? var/list/processing_parts // Component parts queued for processing by the machine. Expected type: `/obj/item/stock_parts` Unused currently - var/processing_flags // Bitflag. What is being processed. One of `MACHINERY_PROCESS_*`. + + /// Bitflag. What is being processed. One of `MACHINERY_PROCESS_*`. + var/processing_flags + var/clicksound //played sound on usage var/clickvol = 40 //volume var/obj/item/device/assembly/signaler/signaler // signaller attached to the machine diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index feda392b14b..1456fbaa866 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -395,18 +395,51 @@ Weaken(FLOOR(stun_duration/2)) return 1 +/** + * Adds an amount of a chemical effect to the mob + * + * * effect - A string indicative of the effect, as per `CE_*` defines in `code\__DEFINES\chemistry.dm` + * * magnitude - The magnitude/quantity/amount of the effect to add + */ /mob/living/carbon/proc/add_chemical_effect(var/effect, var/magnitude = 1) + SHOULD_NOT_SLEEP(TRUE) + if(effect in chem_effects) chem_effects[effect] += magnitude else chem_effects[effect] = magnitude +/** + * Adds _up to_ an amount of a chemical effect to the mob + * + * Makes a chemical effect have _at least_ the specified `magnitude` + * + * * effect - A string indicative of the effect, as per `CE_*` defines in `code\__DEFINES\chemistry.dm` + * * magnitude - The magnitude/quantity/amount of the effect to reach, if lacking + */ /mob/living/carbon/proc/add_up_to_chemical_effect(var/effect, var/magnitude = 1) + SHOULD_NOT_SLEEP(TRUE) + if(effect in chem_effects) chem_effects[effect] = max(magnitude, chem_effects[effect]) else chem_effects[effect] = magnitude +/** + * Removes an amount of a chemical effect from the mob + * + * Prevents the magnitude to go negative + * + * * effect - A string indicative of the effect, as per `CE_*` defines in `code\__DEFINES\chemistry.dm` + * * magnitude - The magnitude/quantity/amount of the effect to remove + */ +/mob/living/carbon/proc/remove_chemical_effect(var/effect, var/magnitude = 1) + SHOULD_NOT_SLEEP(TRUE) + + if(effect in chem_effects) + chem_effects[effect] -= max(magnitude, chem_effects[effect]) + + /mob/living/carbon/get_default_language() if(default_language) return default_language diff --git a/code/modules/power/power_usage.dm b/code/modules/power/power_usage.dm index 417e0464367..db7b6906b58 100644 --- a/code/modules/power/power_usage.dm +++ b/code/modules/power/power_usage.dm @@ -55,7 +55,14 @@ This is /obj/machinery level code to properly manage power usage from the area. else return 0 -// This will have this machine have its area eat this much power next tick, and not afterwards. Do not use for continued power draw. +/** + * This will have this machine have its area eat this much power next tick, and not afterwards + * + * Do not use for continued power draw. + * + * * amount - The amount of power to consume + * * chan - The channel to consume it from, see `code\__DEFINES\machinery.dm` + */ /obj/machinery/proc/use_power_oneoff(var/amount, var/chan = POWER_CHAN) var/area/A = get_area(src) // make sure it's in an area if(!A) diff --git a/code/unit_tests/create_and_destroy.dm b/code/unit_tests/create_and_destroy.dm index 386b698975e..29202d107e8 100644 --- a/code/unit_tests/create_and_destroy.dm +++ b/code/unit_tests/create_and_destroy.dm @@ -43,9 +43,6 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) /obj/machinery/portable_atmospherics/hydroponics/soil/invisible, - // Requires an operating table - /obj/machinery/computer/operating, - // Requires to pick an output at init /obj/machinery/appliance/mixer/, diff --git a/html/changelogs/fluffyghost-optablerefactor.yml b/html/changelogs/fluffyghost-optablerefactor.yml new file mode 100644 index 00000000000..fd4725c56e9 --- /dev/null +++ b/html/changelogs/fluffyghost-optablerefactor.yml @@ -0,0 +1,51 @@ +################################ +# Example Changelog File +# +# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb. +# +# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.) +# When it is, any changes listed below will disappear. +# +# Valid Prefixes: +# bugfix +# wip (For works in progress) +# tweak +# soundadd +# sounddel +# rscadd (general adding of nice things) +# rscdel (general deleting of nice things) +# imageadd +# imagedel +# maptweak +# spellcheck (typo fixes) +# experiment +# balance +# admin +# backend +# security +# refactor +################################# + +# Your name. +author: FluffyGhost + +# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again. +delete-after: True + +# Any changes you've made. See valid prefix list above. +# INDENT WITH TWO SPACES. NOT TABS. SPACES. +# SCREW THIS UP AND IT WON'T WORK. +# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries. +# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog. +changes: + - backend: "Implemented COMSIG_ATOM_ENTERED, COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED and COMSIG_ATOM_EXITING." + - backend: "Unified atom's Entered, Entering and Exited in a single proc." + - backend: "Added remove_chemical_effect proc to remove chemical effect quantities (currently unused)." + - backend: "DMDocs, some SDMM proc markings." + - refactor: "Refactored optable beds." + - rscadd: "Optable beds now use power to suppress the patient's brain." + - bugfix: "The camera getting stuck on optable beds should now be fixed." + - refactor: "Refactored operating computer in how it connects and disconnects with the surgery table." + - backend: "Adjusted integrated bodyscanner to account for tables using weakrefs on patients." + - rscadd: "It should now be possible to reliably build operating tables and consoles and have them hook with each other." + - backend: "Operating tables and operating computers should now delete cleanly."