From d71eb2ef56095b641fe7167330cbe634229fb619 Mon Sep 17 00:00:00 2001 From: atermonera Date: Mon, 13 Mar 2023 23:34:12 -0800 Subject: [PATCH 1/2] Ports extensions from Nebula --- code/_helpers/unsorted.dm | 4 + code/_macros.dm | 2 + code/datums/extensions/_defines.dm | 3 + code/datums/extensions/event_registration.dm | 25 ++++ code/datums/extensions/extensions.dm | 77 ++++++++++++ code/datums/extensions/eye/_eye.dm | 107 +++++++++++++++++ code/datums/extensions/eye/blueprints.dm | 32 +++++ code/datums/extensions/eye/freelook.dm | 12 ++ code/datums/extensions/eye/landing.dm | 26 +++++ code/datums/extensions/interactive.dm | 36 ++++++ code/datums/extensions/label.dm | 110 ++++++++++++++++++ code/datums/extensions/on_click/turf_hand.dm | 20 ++++ code/datums/extensions/state_machine.dm | 99 ++++++++++++++++ code/datums/observation/name_set.dm | 26 +++++ code/datums/repositories/events.dm | 28 +++++ code/datums/state_machine/state.dm | 30 +++++ code/datums/state_machine/transition.dm | 16 +++ code/modules/mob/living/silicon/silicon.dm | 3 +- code/modules/paperwork/handlabeler.dm | 80 +++++++------ .../reagents/machinery/dispenser/cartridge.dm | 27 +++-- polaris.dme | 9 ++ 21 files changed, 724 insertions(+), 48 deletions(-) create mode 100644 code/datums/extensions/_defines.dm create mode 100644 code/datums/extensions/event_registration.dm create mode 100644 code/datums/extensions/extensions.dm create mode 100644 code/datums/extensions/eye/_eye.dm create mode 100644 code/datums/extensions/eye/blueprints.dm create mode 100644 code/datums/extensions/eye/freelook.dm create mode 100644 code/datums/extensions/eye/landing.dm create mode 100644 code/datums/extensions/interactive.dm create mode 100644 code/datums/extensions/label.dm create mode 100644 code/datums/extensions/on_click/turf_hand.dm create mode 100644 code/datums/extensions/state_machine.dm create mode 100644 code/datums/observation/name_set.dm create mode 100644 code/datums/repositories/events.dm create mode 100644 code/datums/state_machine/state.dm create mode 100644 code/datums/state_machine/transition.dm diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm index c7f3022b09f..ec102c2258a 100644 --- a/code/_helpers/unsorted.dm +++ b/code/_helpers/unsorted.dm @@ -1595,3 +1595,7 @@ GLOBAL_REAL_VAR(list/stack_trace_storage) /proc/CallAsync(datum/source, proctype, list/arguments) set waitfor = FALSE return call(source, proctype)(arglist(arguments)) + +// call to generate a stack trace and print to runtime logs +/proc/get_stack_trace(msg, file, line) + CRASH("%% [file],[line] %% [msg]") diff --git a/code/_macros.dm b/code/_macros.dm index 603b7c45e34..72c63735a2d 100644 --- a/code/_macros.dm +++ b/code/_macros.dm @@ -62,3 +62,5 @@ //check if all bitflags specified are present #define CHECK_MULTIPLE_BITFIELDS(flagvar, flags) ((flagvar & (flags)) == flags) + +#define PRINT_STACK_TRACE(X) get_stack_trace(X, __FILE__, __LINE__) diff --git a/code/datums/extensions/_defines.dm b/code/datums/extensions/_defines.dm new file mode 100644 index 00000000000..1f8457bb367 --- /dev/null +++ b/code/datums/extensions/_defines.dm @@ -0,0 +1,3 @@ +#define EXTENSION_FLAG_NONE 0 +#define EXTENSION_FLAG_IMMEDIATE 1 // Instantly instantiates, instead of doing it lazily. +//#define EXTENSION_FLAG_MULTIPLE_INSTANCES 2 // Allows multiple instances per base type. To be implemented diff --git a/code/datums/extensions/event_registration.dm b/code/datums/extensions/event_registration.dm new file mode 100644 index 00000000000..e1eab80928c --- /dev/null +++ b/code/datums/extensions/event_registration.dm @@ -0,0 +1,25 @@ +// For registering for events to be called when certain conditions are met. + +/datum/extension/event_registration + base_type = /datum/extension/event_registration + expected_type = /datum + flags = EXTENSION_FLAG_IMMEDIATE + var/decl/observ/event + var/datum/target + var/callproc + +/datum/extension/event_registration/New(datum/holder, decl/observ/event, datum/target, callproc) + ..() + event.register(target, src, .proc/trigger) + events_repository.register(/decl/observ/destroyed, target, src, .proc/qdel_self) + src.event = event + src.target = target + src.callproc = callproc + +/datum/extension/event_registration/Destroy() + events_repository.unregister(/decl/observ/destroyed, target, src) + event.unregister(target, src) + . = ..() + +/datum/extension/event_registration/proc/trigger() + call(holder, callproc)(arglist(args)) diff --git a/code/datums/extensions/extensions.dm b/code/datums/extensions/extensions.dm new file mode 100644 index 00000000000..969a4c8fbe7 --- /dev/null +++ b/code/datums/extensions/extensions.dm @@ -0,0 +1,77 @@ +/datum/extension + var/base_type + var/datum/holder = null // The holder + var/expected_type = /datum + var/flags = EXTENSION_FLAG_NONE + +/datum/extension/New(var/datum/holder) + if(!istype(holder, expected_type)) + CRASH("Invalid holder type. Expected [expected_type], was [holder.type]") + src.holder = holder + +/datum/extension/proc/post_construction() + +/datum/extension/Destroy() + holder = null + . = ..() + +/datum + var/list/datum/extension/extensions + +//Variadic - Additional positional arguments can be given. Named arguments might not work so well +/proc/set_extension(var/datum/source, var/datum/extension/extension_type) + var/datum/extension/extension_base_type = initial(extension_type.base_type) + if(!ispath(extension_base_type, /datum/extension)) + CRASH("Invalid base type: Expected /datum/extension, was [log_info_line(extension_base_type)]") + if(!ispath(extension_type, extension_base_type)) + CRASH("Invalid extension type: Expected [extension_base_type], was [log_info_line(extension_type)]") + if(!source.extensions) + source.extensions = list() + var/datum/extension/existing_extension = source.extensions[extension_base_type] + if(istype(existing_extension)) + qdel(existing_extension) + + if(initial(extension_base_type.flags) & EXTENSION_FLAG_IMMEDIATE) + var/datum/extension/created = construct_extension_instance(extension_type, source, args.Copy(3)) + source.extensions[extension_base_type] = created + created.post_construction() + return created + + var/list/extension_data = list(extension_type, source) + if(args.len > 2) + extension_data += args.Copy(3) + source.extensions[extension_base_type] = extension_data + +/proc/get_or_create_extension(var/datum/source, var/datum/extension/extension_type) + var/base_type = initial(extension_type.base_type) + if(!has_extension(source, base_type)) + set_extension(arglist(args)) + return get_extension(source, base_type) + +/proc/get_extension(var/datum/source, var/base_type) + if(!source.extensions) + return + . = source.extensions[base_type] + if(!.) + return + if(islist(.)) //a list, so it's expecting to be lazy-loaded + var/list/extension_data = . + var/datum/extension/created = construct_extension_instance(extension_data[1], extension_data[2], extension_data.Copy(3)) + source.extensions[base_type] = created + created.post_construction() + return created + +//Fast way to check if it has an extension, also doesn't trigger instantiation of lazy loaded extensions +/proc/has_extension(var/datum/source, var/base_type) + return !!(source.extensions && source.extensions[base_type]) + +/proc/construct_extension_instance(var/extension_type, var/datum/source, var/list/arguments) + arguments = list(source) + arguments + return new extension_type(arglist(arguments)) + +/proc/remove_extension(var/datum/source, var/base_type) + if(!source.extensions || !source.extensions[base_type]) + return + if(!islist(source.extensions[base_type])) + qdel(source.extensions[base_type]) + LAZYREMOVE(source.extensions, base_type) \ No newline at end of file diff --git a/code/datums/extensions/eye/_eye.dm b/code/datums/extensions/eye/_eye.dm new file mode 100644 index 00000000000..59fc3d66404 --- /dev/null +++ b/code/datums/extensions/eye/_eye.dm @@ -0,0 +1,107 @@ +#define HOLDER_TARGET 0 +#define EYE_TARGET 1 +#define EXTENSION_TARGET 2 + +/datum/extension/eye + base_type = /datum/extension/eye + var/mob/observer/eye/extension_eye + var/eye_type = /mob/observer/eye + var/mob/current_looker + + // Actions used to pass commands from the eye to the holder. Must be subtype of /datum/action/eye. + var/action_type + var/list/actions = list() + +/datum/extension/eye/Destroy() + unlook() + QDEL_NULL_LIST(actions) + . = ..() + +// Create the eye object and give control to the given mob. +/datum/extension/eye/proc/look(var/mob/new_looker, var/list/eye_args) + if(new_looker.eyeobj || current_looker) + return FALSE + + LAZYINSERT(eye_args, get_turf(new_looker), 1) // Make sure that a loc is provided to the eye. + + if(!extension_eye) + extension_eye = new eye_type(arglist(eye_args)) + + current_looker = new_looker + + extension_eye.possess(current_looker) + + if(action_type) + for(var/atype in subtypesof(action_type)) + var/datum/action/eye/action = new atype(src) // Eye actions determine their target based off their own target_type var. + actions += action + action.Grant(current_looker) + + // Manual unlooking for the looker. + var/datum/action/eye/unlook/unlook_action = new(src) + actions += unlook_action + unlook_action.Grant(current_looker) + + // Checks for removing the user from the eye outside of unlook actions. + events_repository.register(/decl/observ/moved, holder, src, /datum/extension/eye/proc/unlook) + events_repository.register(/decl/observ/moved, current_looker, src, /datum/extension/eye/proc/unlook) + + events_repository.register(/decl/observ/destroyed, current_looker, src, /datum/extension/eye/proc/unlook) + events_repository.register(/decl/observ/destroyed, extension_eye, src, /datum/extension/eye/proc/unlook) + + if(isliving(current_looker)) + events_repository.register(/decl/observ/stat_set, current_looker, src, /datum/extension/eye/proc/unlook) + events_repository.register(/decl/observ/logged_out, current_looker, src, /datum/extension/eye/proc/unlook) + + return TRUE + +/datum/extension/eye/proc/unlook() + + events_repository.unregister(/decl/observ/moved, holder, src, /datum/extension/eye/proc/unlook) + events_repository.unregister(/decl/observ/moved, current_looker, src, /datum/extension/eye/proc/unlook) + + events_repository.unregister(/decl/observ/destroyed, current_looker, src, /datum/extension/eye/proc/unlook) + events_repository.unregister(/decl/observ/destroyed, extension_eye, src, /datum/extension/eye/proc/unlook) + + if(isliving(current_looker)) + events_repository.unregister(/decl/observ/stat_set, current_looker, src, /datum/extension/eye/proc/unlook) + events_repository.unregister(/decl/observ/logged_out, current_looker, src, /datum/extension/eye/proc/unlook) + + QDEL_NULL(extension_eye) + + if(current_looker) + for(var/datum/action/A in actions) + A.Remove(current_looker) + + current_looker = null + +/datum/extension/eye/proc/get_eye_turf() + return get_turf(extension_eye) + +/datum/action/eye + action_type = AB_GENERIC + check_flags = AB_CHECK_STUNNED|AB_CHECK_LYING + var/eye_type = /mob/observer/eye/ + var/target_type = HOLDER_TARGET // The relevant owner of the proc to be called by the action. + +/datum/action/eye/New(var/datum/extension/eye/eye_extension) + switch(target_type) + if(HOLDER_TARGET) + return ..(eye_extension.holder) + if(EYE_TARGET) + return ..(eye_extension.extension_eye) + if(EXTENSION_TARGET) + return ..(eye_extension) + else + CRASH("Attempted to generate eye action [src] but an improper target_type ([target_type]) was defined.") + +/datum/action/eye/CheckRemoval(mob/living/user) + if(!user.eyeobj || !istype(user.eyeobj, eye_type)) + return TRUE + +// Every eye created using a subtype of this extension will have this action added for manual unlooking. +/datum/action/eye/unlook + name = "Stop looking" + procname = "unlook" + button_icon_state = "cancel" + target_type = EXTENSION_TARGET diff --git a/code/datums/extensions/eye/blueprints.dm b/code/datums/extensions/eye/blueprints.dm new file mode 100644 index 00000000000..3d6f35616da --- /dev/null +++ b/code/datums/extensions/eye/blueprints.dm @@ -0,0 +1,32 @@ +/datum/extension/eye/blueprints + expected_type = /obj/item/blueprints + eye_type = /mob/observer/eye/blueprints + + action_type = /datum/action/eye/blueprints + +/datum/action/eye/blueprints + eye_type = /mob/observer/eye/blueprints + +/datum/action/eye/blueprints/mark_new_area + name = "Mark new area" + procname = "create_area" + button_icon_state = "pencil" + target_type = EYE_TARGET + +/datum/action/eye/blueprints/remove_selection + name = "Remove selection" + procname = "remove_selection" + button_icon_state = "eraser" + target_type = EYE_TARGET + +/datum/action/eye/blueprints/edit_area + name = "Edit area" + procname = "edit_area" + button_icon_state = "edit_area" + target_type = EYE_TARGET + +/datum/action/eye/blueprints/remove_area + name = "Remove area" + procname = "remove_area" + button_icon_state = "remove_area" + target_type = EYE_TARGET \ No newline at end of file diff --git a/code/datums/extensions/eye/freelook.dm b/code/datums/extensions/eye/freelook.dm new file mode 100644 index 00000000000..a802ea0207a --- /dev/null +++ b/code/datums/extensions/eye/freelook.dm @@ -0,0 +1,12 @@ +// For mobs connecting to the station's cameranet without needing AI procs. +/datum/extension/eye/cameranet + eye_type = /mob/observer/eye/freelook/cameranet + +// For mobs connecting to other visualnets. Pass visualnet as eye_args in look(). +/datum/extension/eye/freelook + eye_type = /mob/observer/eye/freelook + +/datum/extension/eye/freelook/proc/set_visualnet(var/datum/visualnet/net) + if(extension_eye) + var/mob/observer/eye/freelook/fl = extension_eye + if(istype(fl)) fl.visualnet = net \ No newline at end of file diff --git a/code/datums/extensions/eye/landing.dm b/code/datums/extensions/eye/landing.dm new file mode 100644 index 00000000000..c43060f0812 --- /dev/null +++ b/code/datums/extensions/eye/landing.dm @@ -0,0 +1,26 @@ +/datum/extension/eye/landing + expected_type = /obj/machinery/computer/shuttle_control/explore + eye_type = /mob/observer/eye/landing + + action_type = /datum/action/eye/landing + +/datum/extension/eye/landing/get_eye_turf() + var/turf/eye_turf = ..() + var/mob/observer/eye/landing/landing_eye = extension_eye + + return locate(eye_turf.x + landing_eye.x_offset, eye_turf.y + landing_eye.y_offset, eye_turf.z) + +/datum/action/eye/landing + eye_type = /mob/observer/eye/landing + +/datum/action/eye/landing/finish_landing + name = "Set landing location" + procname = "finish_landing" + button_icon_state = "shuttle_land" + target_type = HOLDER_TARGET + +/datum/action/eye/landing/toggle_offsetting + name = "Offset landing location" + procname = "toggle_offsetting" + button_icon_state = "shuttle_offset" + target_type = EYE_TARGET \ No newline at end of file diff --git a/code/datums/extensions/interactive.dm b/code/datums/extensions/interactive.dm new file mode 100644 index 00000000000..c6036f0b2ae --- /dev/null +++ b/code/datums/extensions/interactive.dm @@ -0,0 +1,36 @@ +//Extensions that can be interacted with via Topic +/datum/extension/interactive + base_type = /datum/extension/interactive + var/list/host_predicates + var/list/user_predicates + +/datum/extension/interactive/New(var/datum/holder, var/host_predicates = list(), var/user_predicates = list()) + ..() + + src.host_predicates = host_predicates ? host_predicates : list() + src.user_predicates = user_predicates ? user_predicates : list() + +/datum/extension/interactive/Destroy() + host_predicates.Cut() + user_predicates.Cut() + return ..() + +/datum/extension/interactive/proc/extension_status(var/mob/user) + if(!holder || !user) + return STATUS_CLOSE + if(!all_predicates_true(list(holder), host_predicates)) + return STATUS_CLOSE + if(!all_predicates_true(list(user), user_predicates)) + return STATUS_CLOSE + if(holder.CanUseTopic(user, global.default_topic_state) != STATUS_INTERACTIVE) + return STATUS_CLOSE + + return STATUS_INTERACTIVE + +/datum/extension/interactive/proc/extension_act(var/href, var/list/href_list, var/mob/user) + return extension_status(user) == STATUS_CLOSE + +/datum/extension/interactive/Topic(var/href, var/list/href_list) + if(..()) + return TRUE + return extension_act(href, href_list, usr) \ No newline at end of file diff --git a/code/datums/extensions/label.dm b/code/datums/extensions/label.dm new file mode 100644 index 00000000000..d8bb9cf4b8a --- /dev/null +++ b/code/datums/extensions/label.dm @@ -0,0 +1,110 @@ +/datum/extension/labels + base_type = /datum/extension/labels + expected_type = /atom + var/atom/atom_holder + var/list/labels + +/datum/extension/labels/New() + ..() + atom_holder = holder + +/datum/extension/labels/Destroy() + atom_holder = null + return ..() + +/datum/extension/labels/proc/AttachLabel(var/mob/user, var/label) + if(!CanAttachLabel(user, label)) + return + + if(!LAZYLEN(labels)) + atom_holder.verbs += /atom/proc/RemoveLabel + LAZYADD(labels, label) + + if(user) + user.visible_message("\The [user] attaches a label to \the [atom_holder].", \ + "You attach a label, '[label]', to \the [atom_holder].") + + var/old_name = atom_holder.name + atom_holder.name = "[atom_holder.name] ([label])" + events_repository.raise_event(/decl/observ/name_set, src, old_name, atom_holder.name) + return TRUE + +/datum/extension/labels/proc/RemoveLabel(var/mob/user, var/label) + if(!(label in labels)) + return + + LAZYREMOVE(labels, label) + if(!LAZYLEN(labels)) + atom_holder.verbs -= /atom/proc/RemoveLabel + + var/full_label = " ([label])" + var/index = findtextEx(atom_holder.name, full_label) + if(!index) // Playing it safe, something might not have set the name properly + return + + if(user) + user.visible_message("\The [user] removes a label from \the [atom_holder].", \ + "You remove a label, '[label]', from \the [atom_holder].") + + var/old_name = atom_holder.name + // We find and replace the first instance, since that's the one we removed from the list + atom_holder.name = replacetext(atom_holder.name, full_label, "", index, index + length(full_label)) + events_repository.raise_event(/decl/observ/name_set, src, old_name, atom_holder.name) + return TRUE + +/datum/extension/labels/proc/RemoveAllLabels() + . = TRUE + for(var/lbl in labels) + if(!RemoveLabel(null, lbl)) + . = FALSE + +// We may have to do something more complex here +// in case something appends strings to something that's labelled rather than replace the name outright +// Non-printable characters should be of help if this comes up +/datum/extension/labels/proc/AppendLabelsToName(var/name) + if(!LAZYLEN(labels)) + return name + . = list(name) + for(var/entry in labels) + . += " ([entry])" + . = jointext(., null) + +/datum/extension/labels/proc/CanAttachLabel(var/user, var/label) + if(!length(label)) + return FALSE + if(ExcessLabelLength(label, user)) + return FALSE + return TRUE + +/datum/extension/labels/proc/ExcessLabelLength(var/label, var/user) + . = length(label) + 3 // Each label also adds a space and two brackets when applied to a name + if(LAZYLEN(labels)) + for(var/entry in labels) + . += length(entry) + 3 + . = . > 64 ? TRUE : FALSE + if(. && user) + to_chat(user, "The label won't fit.") + +/proc/get_attached_labels(var/atom/source) + if(has_extension(source, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(source, /datum/extension/labels) + if(LAZYLEN(L.labels)) + return L.labels.Copy() + return list() + +/atom/proc/RemoveLabel(var/label in get_attached_labels(src)) + set name = "Remove Label" + set desc = "Used to remove labels" + set category = "Object" + set src in view(1) + + if(Adjacent(usr)) + if(has_extension(src, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(src, /datum/extension/labels) + L.RemoveLabel(usr, label) + +//Single label allowed for this one +/datum/extension/labels/single/CanAttachLabel(user, label) + if(LAZYLEN(labels) >= 1) //Only allow a single label + return FALSE + . = ..() diff --git a/code/datums/extensions/on_click/turf_hand.dm b/code/datums/extensions/on_click/turf_hand.dm new file mode 100644 index 00000000000..b3ab8a38104 --- /dev/null +++ b/code/datums/extensions/on_click/turf_hand.dm @@ -0,0 +1,20 @@ +/* + This extension is used on airlocks and cult runes. + When a mob [attack_hand]s a turf, it will look for objects in itself containing this component. + If such is found, it will call attack_hand on that atom + + When multiple of these components are in the tile, the one with the highest priority wins it. +*/ +/datum/extension/turf_hand + base_type = /datum/extension/turf_hand + var/priority = 1 + expected_type = /atom + +/datum/extension/turf_hand/New(var/holder, var/priority = 1) + ..() + src.priority = priority + + +/datum/extension/turf_hand/proc/OnHandInterception(var/mob/user) + var/atom/A = holder + return A.attack_hand(user) \ No newline at end of file diff --git a/code/datums/extensions/state_machine.dm b/code/datums/extensions/state_machine.dm new file mode 100644 index 00000000000..4d573c68494 --- /dev/null +++ b/code/datums/extensions/state_machine.dm @@ -0,0 +1,99 @@ +// List and procs for caching state machine instances. +var/global/list/state_machines = list() + +/proc/get_state_machine(var/datum/holder, var/base_type) + if(istype(holder) && base_type) + var/list/machines = global.state_machines["\ref[holder]"] + return islist(machines) && machines[base_type] + +/proc/add_state_machine(var/datum/holder, var/base_type, var/fsm_type) + if(istype(holder) && base_type) + var/holder_ref = "\ref[holder]" + var/list/machines = global.state_machines[holder_ref] + if(!islist(machines)) + machines = list() + global.state_machines[holder_ref] = machines + if(!machines[base_type]) + if(!fsm_type) + fsm_type = base_type + var/datum/state_machine/machine = new fsm_type(holder) + machines[base_type] = machine + return machine + +/proc/remove_state_machine(var/datum/holder, var/base_type) + if(istype(holder) && base_type) + var/holder_ref = "\ref[holder]" + var/list/machines = global.state_machines[holder_ref] + if(length(machines)) + machines -= base_type + if(!length(machines)) + global.state_machines -= holder_ref + return TRUE + return FALSE + +// This contains the current state of the FSM and should be held by whatever the FSM is controlling. +// Unlike the individual states and their transitions, the state machine objects are not singletons, and hence aren't `/decl`s. +/datum/state_machine + var/weakref/holder_ref + var/base_type = /datum/state_machine + var/expected_type = /datum + var/decl/state/current_state = null // Acts both as a ref to the current state and holds which state it will default to on init. + +/datum/state_machine/New(var/datum/_holder) + ..() + if(!istype(_holder)) + PRINT_STACK_TRACE("Non-datum holder supplied to [type] New().") + else + holder_ref = weakref(_holder) + set_state(current_state) + +/datum/state_machine/Destroy() + current_state = null + return ..() + +// Resets back to our initial state. +/datum/state_machine/proc/reset() + var/datum/holder_instance = get_holder() + if(istype(current_state)) + current_state.exited_state(holder_instance) + current_state = initial(current_state) + if(ispath(current_state, /decl/state)) + current_state = GET_DECL(current_state) + current_state.entered_state(holder_instance) + else + current_state = null + return current_state + +// Retrieve and validate our holder instance from the cached weakref. +/datum/state_machine/proc/get_holder() + var/datum/holder = holder_ref?.resolve() + if(istype(holder) && !QDELETED(holder)) + return holder + +// Makes the FSM enter a new state, if it can, based on it's current state, that state's transitions, and the holder's status. +// Call it in the holder's `process()`, or whenever you need to. +/datum/state_machine/proc/evaluate() + var/datum/holder_instance = get_holder() + var/list/options = current_state.get_open_transitions(holder_instance) + if(LAZYLEN(options)) + var/decl/state_transition/choice = choose_transition(options) + current_state.exited_state(holder_instance) + current_state = choice.target + current_state.entered_state(holder_instance) + return current_state + +// Decides which transition to walk into, to the next state. +// By default it chooses the first one on the list. +/datum/state_machine/proc/choose_transition(list/valid_transitions) + return valid_transitions[1] + +// Forces the FSM to switch to a specific state, no matter what. +// Use responsibly. +/datum/state_machine/proc/set_state(new_state_type) + var/datum/holder_instance = get_holder() + if(istype(current_state)) + current_state.exited_state(holder_instance) + current_state = GET_DECL(new_state_type) + if(istype(current_state)) + current_state.entered_state(holder_instance) + return current_state diff --git a/code/datums/observation/name_set.dm b/code/datums/observation/name_set.dm new file mode 100644 index 00000000000..c4c52381c04 --- /dev/null +++ b/code/datums/observation/name_set.dm @@ -0,0 +1,26 @@ +// Observer Pattern Implementation: Name Set +// Registration type: /atom +// +// Raised when: An atom's name changes. +// +// Arguments that the called proc should expect: +// /atom/namee: The atom that had its name set +// /old_name: name before the change +// /new_name: name after the change + +/decl/observ/name_set + name = "Name Set" + expected_type = /atom + +/********************* +* Name Set Handling * +*********************/ + +/atom/proc/SetName(var/new_name) + var/old_name = name + if(old_name != new_name) + name = new_name + if(has_extension(src, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(src, /datum/extension/labels) + name = L.AppendLabelsToName(name) + events_repository.raise_event(/decl/observ/name_set, src, old_name, new_name) diff --git a/code/datums/repositories/events.dm b/code/datums/repositories/events.dm new file mode 100644 index 00000000000..ce7dca9f076 --- /dev/null +++ b/code/datums/repositories/events.dm @@ -0,0 +1,28 @@ +// Essentially just a wrapper for /decl/observ to preserve init order/make sure they aren't new'd at runtime. + +var/global/repository/events/events_repository = new + +/repository/events/proc/raise_event(var/event_type) + var/decl/observ/event = GET_DECL(event_type) + if(event) + event.raise_event(arglist(args.Copy(2))) + +/repository/events/proc/register(var/event_type, var/datum/event_source, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + event.register(event_source, listener, proc_call) + +/repository/events/proc/unregister(var/event_type, var/datum/event_source, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + event.unregister(event_source, listener, proc_call) + +/repository/events/proc/register_global(var/event_type, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + event.register_global(listener, proc_call) + +/repository/events/proc/unregister_global(var/event_type, var/datum/listener, var/proc_call) + var/decl/observ/event = GET_DECL(event_type) + if(event) + event.unregister_global(listener, proc_call) diff --git a/code/datums/state_machine/state.dm b/code/datums/state_machine/state.dm new file mode 100644 index 00000000000..55bb1a93fff --- /dev/null +++ b/code/datums/state_machine/state.dm @@ -0,0 +1,30 @@ +// An individual state, defined as a `/decl` to save memory. +// On a directed graph, these would be the nodes themselves, connected to each other by unidirectional arrows. +/decl/state + // Transition decl types, which get turned into refs to those types. + // Note that the order DOES matter, as decls earlier in the list have higher priority + // if more than one becomes 'open'. + var/list/transitions = null + +/decl/state/Initialize() + . = ..() + for(var/i in 1 to LAZYLEN(transitions)) + var/decl/state_transition/T = GET_DECL(transitions[i]) + T.from += src + transitions[i] = T + +// Returns a list of transitions that a FSM could switch to. +// Note that `holder` is NOT the FSM, but instead the thing the FSM is attached to. +/decl/state/proc/get_open_transitions(datum/holder) + for(var/decl/state_transition/T as anything in transitions) + if(T.is_open(holder)) + LAZYADD(., T) + +// Stub for child states to modify the holder when switched to. +// Again, `holder` is not the FSM. +/decl/state/proc/entered_state(datum/holder) + return + +// Another stub for when leaving a state. +/decl/state/proc/exited_state(datum/holder) + return \ No newline at end of file diff --git a/code/datums/state_machine/transition.dm b/code/datums/state_machine/transition.dm new file mode 100644 index 00000000000..ade5daf683a --- /dev/null +++ b/code/datums/state_machine/transition.dm @@ -0,0 +1,16 @@ +// Used to connect `/decl/state`s together so the FSM knows what state to switch to, and on what conditions. +// On a directed graph, these would be the arrows connecting the nodes representing states. +/decl/state_transition + var/list/from = null + var/decl/state/target = null + +// Called by one or more state decls acting as nodes in a directed graph. +/decl/state_transition/Initialize() + . = ..() + LAZYINITLIST(from) + if(ispath(target)) + target = GET_DECL(target) + +// Tells the FSM if it should or should not be allowed to transfer to the target state. +/decl/state_transition/proc/is_open(datum/holder) + return FALSE \ No newline at end of file diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 1526cc959dd..7b27e55cb47 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -49,9 +49,10 @@ idcard = new idcard_type(src) set_id_info(idcard) -/mob/living/silicon/proc/SetName(pickedName as text) +/mob/living/silicon/SetName(pickedName as text) real_name = pickedName name = real_name + ..() /mob/living/silicon/proc/show_laws() return diff --git a/code/modules/paperwork/handlabeler.dm b/code/modules/paperwork/handlabeler.dm index 0162fa479f9..f9c68a99049 100644 --- a/code/modules/paperwork/handlabeler.dm +++ b/code/modules/paperwork/handlabeler.dm @@ -29,43 +29,53 @@ if(length(A.name) + length(label) > 64) to_chat(user, SPAN_WARNING("\The [src]'s label too big.")) return - if(istype(A, /mob/living/silicon/robot/platform)) - var/mob/living/silicon/robot/platform/P = A - if(!P.allowed(user)) - to_chat(usr, SPAN_WARNING("Access denied.")) - else if(P.client || P.key) - to_chat(user, SPAN_NOTICE("You rename \the [P] to [label].")) - to_chat(P, SPAN_NOTICE("\The [user] renames you to [label].")) - P.custom_name = label - P.SetName(P.custom_name) - else - to_chat(user, SPAN_WARNING("\The [src] is inactive and cannot be renamed.")) - return - if(ishuman(A)) - to_chat(user, SPAN_WARNING("The label refuses to stick to [A.name].")) - return - if(issilicon(A)) - to_chat(user, SPAN_WARNING("The label refuses to stick to [A.name].")) - return - if(isobserver(A)) - to_chat(user, SPAN_WARNING("[src] passes through [A.name].")) + + if(has_extension(A, /datum/extension/labels)) + var/datum/extension/labels/L = get_extension(A, /datum/extension/labels) + if(!L.CanAttachLabel(user, label)) + return + A.attach_label(user, src, label) + +/atom/proc/attach_label(var/user, var/atom/labeler, var/label_text) + to_chat(user, "The label refuses to stick to [name].") + +/mob/observer/attach_label(var/user, var/atom/labeler, var/label_text) + to_chat(user, "\The [labeler] passes through \the [src].") + +/obj/machinery/portable_atmospherics/hydroponics/attach_label(var/user, var/atom/labeler, var/label_text) + if(!mechanical) + to_chat(user, "How are you going to label that?") return - if(istype(A, /obj/item/reagent_containers/glass)) - to_chat(user, SPAN_WARNING("The label can't stick to the [A.name] (Try using a pen).")) + ..() + update_icon() + +/obj/attach_label(var/user, var/atom/labeler, var/label_text) + if(!simulated) return - if(istype(A, /obj/machinery/portable_atmospherics/hydroponics)) - var/obj/machinery/portable_atmospherics/hydroponics/tray = A - if(!tray.mechanical) - to_chat(user, SPAN_WARNING("How are you going to label that?")) - return - tray.labelled = label - spawn(1) - tray.update_icon() + var/datum/extension/labels/L = get_or_create_extension(src, /datum/extension/labels) + return L.AttachLabel(user, label_text) + +/mob/living/silicon/robot/platform/attach_label(var/user, var/atom/labeler, var/label_text) + if(!allowed(user)) + to_chat(usr, SPAN_WARNING("Access denied.")) + else if(client || key) + to_chat(user, SPAN_NOTICE("You rename \the [src] to [label_text].")) + to_chat(src, SPAN_NOTICE("\The [user] renames you to [label_text].")) + SetName(label_text) + else + to_chat(user, SPAN_WARNING("\The [src] is inactive and cannot be renamed.")) - user.visible_message( \ - SPAN_NOTICE("\The [user] labels [A] as [label]."), \ - SPAN_NOTICE("You label [A] as [label].")) - A.name = "[A.name] ([label])" +/obj/item/reagent_containers/glass/attach_label(var/user, var/atom/labeler, var/label_text) + to_chat(user, SPAN_WARNING("The label can't stick to the [name] (Try using a pen).")) + return + +/obj/machinery/portable_atmospherics/hydroponics/attach_label(var/user, var/atom/labeler, var/label_text) + if(!mechanical) + to_chat(user, SPAN_WARNING("How are you going to label that?")) + return + ..() + spawn(1) + update_icon() /obj/item/hand_labeler/attack_self(mob/user as mob) mode = !mode @@ -80,4 +90,4 @@ label = str to_chat(user, SPAN_NOTICE("You set the text to '[str]'.")) else - to_chat(user, SPAN_NOTICE("You turn off \the [src].")) \ No newline at end of file + to_chat(user, SPAN_NOTICE("You turn off \the [src].")) diff --git a/code/modules/reagents/machinery/dispenser/cartridge.dm b/code/modules/reagents/machinery/dispenser/cartridge.dm index f01b8c1f046..9acb6aabd65 100644 --- a/code/modules/reagents/machinery/dispenser/cartridge.dm +++ b/code/modules/reagents/machinery/dispenser/cartridge.dm @@ -36,20 +36,23 @@ set category = "Object" set src in view(usr, 1) - setLabel(L, usr) + var/datum/extension/labels/lext = get_or_create_extension(src, /datum/extension/labels) + if(lext) + for(var/lab in lext.labels) + lext.RemoveLabel(null, lab) + if(length(L)) + lext.AttachLabel(null, L) /obj/item/reagent_containers/chem_disp_cartridge/proc/setLabel(L, mob/user = null) - if(L) - if(user) - to_chat(user, "You set the label on \the [src] to '[L]'.") - - label = L - name = "[initial(name)] - '[L]'" - else - if(user) - to_chat(user, "You clear the label on \the [src].") - label = "" - name = initial(name) + var/datum/extension/labels/lext = get_or_create_extension(src, /datum/extension/labels) + if(lext) + for(var/lab in lext.labels) + lext.RemoveLabel(null, lab) + + if(length(L)) + lext.AttachLabel(user, L) + else if(user) + to_chat(user, SPAN_NOTICE("You clear the label on \the [src].")) /obj/item/reagent_containers/chem_disp_cartridge/attack_self() ..() diff --git a/polaris.dme b/polaris.dme index 48fd42a51f5..0a721026777 100644 --- a/polaris.dme +++ b/polaris.dme @@ -310,6 +310,11 @@ #include "code\datums\components\crafting\tool_quality.dm" #include "code\datums\components\crafting\recipes\archery.dm" #include "code\datums\elements\_element.dm" +#include "code\datums\extensions\_defines.dm" +#include "code\datums\extensions\event_registration.dm" +#include "code\datums\extensions\extensions.dm" +#include "code\datums\extensions\label.dm" +#include "code\datums\extensions\state_machine.dm" #include "code\datums\game_masters\_common.dm" #include "code\datums\game_masters\default.dm" #include "code\datums\game_masters\other_game_masters.dm" @@ -344,6 +349,7 @@ #include "code\datums\observation\helpers.dm" #include "code\datums\observation\logged_in.dm" #include "code\datums\observation\moved.dm" +#include "code\datums\observation\name_set.dm" #include "code\datums\observation\observation.dm" #include "code\datums\observation\power_change.dm" #include "code\datums\observation\shuttle_added.dm" @@ -383,11 +389,14 @@ #include "code\datums\repositories\cameras.dm" #include "code\datums\repositories\crew.dm" #include "code\datums\repositories\decls.dm" +#include "code\datums\repositories\events.dm" #include "code\datums\repositories\repository.dm" #include "code\datums\repositories\unique.dm" #include "code\datums\roundstats\_defines_local.dm" #include "code\datums\roundstats\departmentgoal.dm" #include "code\datums\roundstats\roundstats.dm" +#include "code\datums\state_machine\state.dm" +#include "code\datums\state_machine\transition.dm" #include "code\datums\supplypacks\atmospherics.dm" #include "code\datums\supplypacks\contraband.dm" #include "code\datums\supplypacks\costumes.dm" From 28d647501d64cb971dca98e5dc3a294610ce5020 Mon Sep 17 00:00:00 2001 From: atermonera Date: Tue, 14 Mar 2023 00:19:11 -0800 Subject: [PATCH 2/2] Addresses PR comments Snips unused code --- code/datums/extensions/_defines.dm | 3 +- code/datums/extensions/event_registration.dm | 5 +- code/datums/extensions/eye/_eye.dm | 107 ------------------- code/datums/extensions/eye/blueprints.dm | 32 ------ code/datums/extensions/eye/freelook.dm | 12 --- code/datums/extensions/eye/landing.dm | 26 ----- code/datums/extensions/label.dm | 6 +- code/datums/extensions/on_click/turf_hand.dm | 20 ---- code/datums/extensions/state_machine.dm | 99 ----------------- code/datums/observation/name_set.dm | 4 +- code/datums/repositories/events.dm | 28 ----- code/modules/mob/living/silicon/silicon.dm | 4 +- polaris.dme | 2 - 13 files changed, 13 insertions(+), 335 deletions(-) delete mode 100644 code/datums/extensions/eye/_eye.dm delete mode 100644 code/datums/extensions/eye/blueprints.dm delete mode 100644 code/datums/extensions/eye/freelook.dm delete mode 100644 code/datums/extensions/eye/landing.dm delete mode 100644 code/datums/extensions/on_click/turf_hand.dm delete mode 100644 code/datums/extensions/state_machine.dm delete mode 100644 code/datums/repositories/events.dm diff --git a/code/datums/extensions/_defines.dm b/code/datums/extensions/_defines.dm index 1f8457bb367..7aa1d04638e 100644 --- a/code/datums/extensions/_defines.dm +++ b/code/datums/extensions/_defines.dm @@ -1,3 +1,2 @@ #define EXTENSION_FLAG_NONE 0 -#define EXTENSION_FLAG_IMMEDIATE 1 // Instantly instantiates, instead of doing it lazily. -//#define EXTENSION_FLAG_MULTIPLE_INSTANCES 2 // Allows multiple instances per base type. To be implemented +#define EXTENSION_FLAG_IMMEDIATE 1 // Instantly instantiates, instead of doing it lazily. diff --git a/code/datums/extensions/event_registration.dm b/code/datums/extensions/event_registration.dm index e1eab80928c..fc18dcfd86e 100644 --- a/code/datums/extensions/event_registration.dm +++ b/code/datums/extensions/event_registration.dm @@ -11,13 +11,14 @@ /datum/extension/event_registration/New(datum/holder, decl/observ/event, datum/target, callproc) ..() event.register(target, src, .proc/trigger) - events_repository.register(/decl/observ/destroyed, target, src, .proc/qdel_self) + GLOB.destroyed_event.register(target, src, .proc/qdel_self) + src.event = event src.target = target src.callproc = callproc /datum/extension/event_registration/Destroy() - events_repository.unregister(/decl/observ/destroyed, target, src) + GLOB.destroyed_event.unregister(target, src, .proc/qdel_self) event.unregister(target, src) . = ..() diff --git a/code/datums/extensions/eye/_eye.dm b/code/datums/extensions/eye/_eye.dm deleted file mode 100644 index 59fc3d66404..00000000000 --- a/code/datums/extensions/eye/_eye.dm +++ /dev/null @@ -1,107 +0,0 @@ -#define HOLDER_TARGET 0 -#define EYE_TARGET 1 -#define EXTENSION_TARGET 2 - -/datum/extension/eye - base_type = /datum/extension/eye - var/mob/observer/eye/extension_eye - var/eye_type = /mob/observer/eye - var/mob/current_looker - - // Actions used to pass commands from the eye to the holder. Must be subtype of /datum/action/eye. - var/action_type - var/list/actions = list() - -/datum/extension/eye/Destroy() - unlook() - QDEL_NULL_LIST(actions) - . = ..() - -// Create the eye object and give control to the given mob. -/datum/extension/eye/proc/look(var/mob/new_looker, var/list/eye_args) - if(new_looker.eyeobj || current_looker) - return FALSE - - LAZYINSERT(eye_args, get_turf(new_looker), 1) // Make sure that a loc is provided to the eye. - - if(!extension_eye) - extension_eye = new eye_type(arglist(eye_args)) - - current_looker = new_looker - - extension_eye.possess(current_looker) - - if(action_type) - for(var/atype in subtypesof(action_type)) - var/datum/action/eye/action = new atype(src) // Eye actions determine their target based off their own target_type var. - actions += action - action.Grant(current_looker) - - // Manual unlooking for the looker. - var/datum/action/eye/unlook/unlook_action = new(src) - actions += unlook_action - unlook_action.Grant(current_looker) - - // Checks for removing the user from the eye outside of unlook actions. - events_repository.register(/decl/observ/moved, holder, src, /datum/extension/eye/proc/unlook) - events_repository.register(/decl/observ/moved, current_looker, src, /datum/extension/eye/proc/unlook) - - events_repository.register(/decl/observ/destroyed, current_looker, src, /datum/extension/eye/proc/unlook) - events_repository.register(/decl/observ/destroyed, extension_eye, src, /datum/extension/eye/proc/unlook) - - if(isliving(current_looker)) - events_repository.register(/decl/observ/stat_set, current_looker, src, /datum/extension/eye/proc/unlook) - events_repository.register(/decl/observ/logged_out, current_looker, src, /datum/extension/eye/proc/unlook) - - return TRUE - -/datum/extension/eye/proc/unlook() - - events_repository.unregister(/decl/observ/moved, holder, src, /datum/extension/eye/proc/unlook) - events_repository.unregister(/decl/observ/moved, current_looker, src, /datum/extension/eye/proc/unlook) - - events_repository.unregister(/decl/observ/destroyed, current_looker, src, /datum/extension/eye/proc/unlook) - events_repository.unregister(/decl/observ/destroyed, extension_eye, src, /datum/extension/eye/proc/unlook) - - if(isliving(current_looker)) - events_repository.unregister(/decl/observ/stat_set, current_looker, src, /datum/extension/eye/proc/unlook) - events_repository.unregister(/decl/observ/logged_out, current_looker, src, /datum/extension/eye/proc/unlook) - - QDEL_NULL(extension_eye) - - if(current_looker) - for(var/datum/action/A in actions) - A.Remove(current_looker) - - current_looker = null - -/datum/extension/eye/proc/get_eye_turf() - return get_turf(extension_eye) - -/datum/action/eye - action_type = AB_GENERIC - check_flags = AB_CHECK_STUNNED|AB_CHECK_LYING - var/eye_type = /mob/observer/eye/ - var/target_type = HOLDER_TARGET // The relevant owner of the proc to be called by the action. - -/datum/action/eye/New(var/datum/extension/eye/eye_extension) - switch(target_type) - if(HOLDER_TARGET) - return ..(eye_extension.holder) - if(EYE_TARGET) - return ..(eye_extension.extension_eye) - if(EXTENSION_TARGET) - return ..(eye_extension) - else - CRASH("Attempted to generate eye action [src] but an improper target_type ([target_type]) was defined.") - -/datum/action/eye/CheckRemoval(mob/living/user) - if(!user.eyeobj || !istype(user.eyeobj, eye_type)) - return TRUE - -// Every eye created using a subtype of this extension will have this action added for manual unlooking. -/datum/action/eye/unlook - name = "Stop looking" - procname = "unlook" - button_icon_state = "cancel" - target_type = EXTENSION_TARGET diff --git a/code/datums/extensions/eye/blueprints.dm b/code/datums/extensions/eye/blueprints.dm deleted file mode 100644 index 3d6f35616da..00000000000 --- a/code/datums/extensions/eye/blueprints.dm +++ /dev/null @@ -1,32 +0,0 @@ -/datum/extension/eye/blueprints - expected_type = /obj/item/blueprints - eye_type = /mob/observer/eye/blueprints - - action_type = /datum/action/eye/blueprints - -/datum/action/eye/blueprints - eye_type = /mob/observer/eye/blueprints - -/datum/action/eye/blueprints/mark_new_area - name = "Mark new area" - procname = "create_area" - button_icon_state = "pencil" - target_type = EYE_TARGET - -/datum/action/eye/blueprints/remove_selection - name = "Remove selection" - procname = "remove_selection" - button_icon_state = "eraser" - target_type = EYE_TARGET - -/datum/action/eye/blueprints/edit_area - name = "Edit area" - procname = "edit_area" - button_icon_state = "edit_area" - target_type = EYE_TARGET - -/datum/action/eye/blueprints/remove_area - name = "Remove area" - procname = "remove_area" - button_icon_state = "remove_area" - target_type = EYE_TARGET \ No newline at end of file diff --git a/code/datums/extensions/eye/freelook.dm b/code/datums/extensions/eye/freelook.dm deleted file mode 100644 index a802ea0207a..00000000000 --- a/code/datums/extensions/eye/freelook.dm +++ /dev/null @@ -1,12 +0,0 @@ -// For mobs connecting to the station's cameranet without needing AI procs. -/datum/extension/eye/cameranet - eye_type = /mob/observer/eye/freelook/cameranet - -// For mobs connecting to other visualnets. Pass visualnet as eye_args in look(). -/datum/extension/eye/freelook - eye_type = /mob/observer/eye/freelook - -/datum/extension/eye/freelook/proc/set_visualnet(var/datum/visualnet/net) - if(extension_eye) - var/mob/observer/eye/freelook/fl = extension_eye - if(istype(fl)) fl.visualnet = net \ No newline at end of file diff --git a/code/datums/extensions/eye/landing.dm b/code/datums/extensions/eye/landing.dm deleted file mode 100644 index c43060f0812..00000000000 --- a/code/datums/extensions/eye/landing.dm +++ /dev/null @@ -1,26 +0,0 @@ -/datum/extension/eye/landing - expected_type = /obj/machinery/computer/shuttle_control/explore - eye_type = /mob/observer/eye/landing - - action_type = /datum/action/eye/landing - -/datum/extension/eye/landing/get_eye_turf() - var/turf/eye_turf = ..() - var/mob/observer/eye/landing/landing_eye = extension_eye - - return locate(eye_turf.x + landing_eye.x_offset, eye_turf.y + landing_eye.y_offset, eye_turf.z) - -/datum/action/eye/landing - eye_type = /mob/observer/eye/landing - -/datum/action/eye/landing/finish_landing - name = "Set landing location" - procname = "finish_landing" - button_icon_state = "shuttle_land" - target_type = HOLDER_TARGET - -/datum/action/eye/landing/toggle_offsetting - name = "Offset landing location" - procname = "toggle_offsetting" - button_icon_state = "shuttle_offset" - target_type = EYE_TARGET \ No newline at end of file diff --git a/code/datums/extensions/label.dm b/code/datums/extensions/label.dm index d8bb9cf4b8a..8c0ffc490bc 100644 --- a/code/datums/extensions/label.dm +++ b/code/datums/extensions/label.dm @@ -26,7 +26,8 @@ var/old_name = atom_holder.name atom_holder.name = "[atom_holder.name] ([label])" - events_repository.raise_event(/decl/observ/name_set, src, old_name, atom_holder.name) + var/decl/observ/name_set/N = GET_DECL(/decl/observ/name_set) + N.raise_event(src, old_name, atom_holder.name) return TRUE /datum/extension/labels/proc/RemoveLabel(var/mob/user, var/label) @@ -49,7 +50,8 @@ var/old_name = atom_holder.name // We find and replace the first instance, since that's the one we removed from the list atom_holder.name = replacetext(atom_holder.name, full_label, "", index, index + length(full_label)) - events_repository.raise_event(/decl/observ/name_set, src, old_name, atom_holder.name) + var/decl/observ/name_set/N = GET_DECL(/decl/observ/name_set) + N.raise_event(src, old_name, atom_holder.name) return TRUE /datum/extension/labels/proc/RemoveAllLabels() diff --git a/code/datums/extensions/on_click/turf_hand.dm b/code/datums/extensions/on_click/turf_hand.dm deleted file mode 100644 index b3ab8a38104..00000000000 --- a/code/datums/extensions/on_click/turf_hand.dm +++ /dev/null @@ -1,20 +0,0 @@ -/* - This extension is used on airlocks and cult runes. - When a mob [attack_hand]s a turf, it will look for objects in itself containing this component. - If such is found, it will call attack_hand on that atom - - When multiple of these components are in the tile, the one with the highest priority wins it. -*/ -/datum/extension/turf_hand - base_type = /datum/extension/turf_hand - var/priority = 1 - expected_type = /atom - -/datum/extension/turf_hand/New(var/holder, var/priority = 1) - ..() - src.priority = priority - - -/datum/extension/turf_hand/proc/OnHandInterception(var/mob/user) - var/atom/A = holder - return A.attack_hand(user) \ No newline at end of file diff --git a/code/datums/extensions/state_machine.dm b/code/datums/extensions/state_machine.dm deleted file mode 100644 index 4d573c68494..00000000000 --- a/code/datums/extensions/state_machine.dm +++ /dev/null @@ -1,99 +0,0 @@ -// List and procs for caching state machine instances. -var/global/list/state_machines = list() - -/proc/get_state_machine(var/datum/holder, var/base_type) - if(istype(holder) && base_type) - var/list/machines = global.state_machines["\ref[holder]"] - return islist(machines) && machines[base_type] - -/proc/add_state_machine(var/datum/holder, var/base_type, var/fsm_type) - if(istype(holder) && base_type) - var/holder_ref = "\ref[holder]" - var/list/machines = global.state_machines[holder_ref] - if(!islist(machines)) - machines = list() - global.state_machines[holder_ref] = machines - if(!machines[base_type]) - if(!fsm_type) - fsm_type = base_type - var/datum/state_machine/machine = new fsm_type(holder) - machines[base_type] = machine - return machine - -/proc/remove_state_machine(var/datum/holder, var/base_type) - if(istype(holder) && base_type) - var/holder_ref = "\ref[holder]" - var/list/machines = global.state_machines[holder_ref] - if(length(machines)) - machines -= base_type - if(!length(machines)) - global.state_machines -= holder_ref - return TRUE - return FALSE - -// This contains the current state of the FSM and should be held by whatever the FSM is controlling. -// Unlike the individual states and their transitions, the state machine objects are not singletons, and hence aren't `/decl`s. -/datum/state_machine - var/weakref/holder_ref - var/base_type = /datum/state_machine - var/expected_type = /datum - var/decl/state/current_state = null // Acts both as a ref to the current state and holds which state it will default to on init. - -/datum/state_machine/New(var/datum/_holder) - ..() - if(!istype(_holder)) - PRINT_STACK_TRACE("Non-datum holder supplied to [type] New().") - else - holder_ref = weakref(_holder) - set_state(current_state) - -/datum/state_machine/Destroy() - current_state = null - return ..() - -// Resets back to our initial state. -/datum/state_machine/proc/reset() - var/datum/holder_instance = get_holder() - if(istype(current_state)) - current_state.exited_state(holder_instance) - current_state = initial(current_state) - if(ispath(current_state, /decl/state)) - current_state = GET_DECL(current_state) - current_state.entered_state(holder_instance) - else - current_state = null - return current_state - -// Retrieve and validate our holder instance from the cached weakref. -/datum/state_machine/proc/get_holder() - var/datum/holder = holder_ref?.resolve() - if(istype(holder) && !QDELETED(holder)) - return holder - -// Makes the FSM enter a new state, if it can, based on it's current state, that state's transitions, and the holder's status. -// Call it in the holder's `process()`, or whenever you need to. -/datum/state_machine/proc/evaluate() - var/datum/holder_instance = get_holder() - var/list/options = current_state.get_open_transitions(holder_instance) - if(LAZYLEN(options)) - var/decl/state_transition/choice = choose_transition(options) - current_state.exited_state(holder_instance) - current_state = choice.target - current_state.entered_state(holder_instance) - return current_state - -// Decides which transition to walk into, to the next state. -// By default it chooses the first one on the list. -/datum/state_machine/proc/choose_transition(list/valid_transitions) - return valid_transitions[1] - -// Forces the FSM to switch to a specific state, no matter what. -// Use responsibly. -/datum/state_machine/proc/set_state(new_state_type) - var/datum/holder_instance = get_holder() - if(istype(current_state)) - current_state.exited_state(holder_instance) - current_state = GET_DECL(new_state_type) - if(istype(current_state)) - current_state.entered_state(holder_instance) - return current_state diff --git a/code/datums/observation/name_set.dm b/code/datums/observation/name_set.dm index c4c52381c04..3eab52425a2 100644 --- a/code/datums/observation/name_set.dm +++ b/code/datums/observation/name_set.dm @@ -23,4 +23,6 @@ if(has_extension(src, /datum/extension/labels)) var/datum/extension/labels/L = get_extension(src, /datum/extension/labels) name = L.AppendLabelsToName(name) - events_repository.raise_event(/decl/observ/name_set, src, old_name, new_name) + + var/decl/observ/name_set/N = GET_DECL(/decl/observ/name_set) + N.raise_event(src, old_name, name) diff --git a/code/datums/repositories/events.dm b/code/datums/repositories/events.dm deleted file mode 100644 index ce7dca9f076..00000000000 --- a/code/datums/repositories/events.dm +++ /dev/null @@ -1,28 +0,0 @@ -// Essentially just a wrapper for /decl/observ to preserve init order/make sure they aren't new'd at runtime. - -var/global/repository/events/events_repository = new - -/repository/events/proc/raise_event(var/event_type) - var/decl/observ/event = GET_DECL(event_type) - if(event) - event.raise_event(arglist(args.Copy(2))) - -/repository/events/proc/register(var/event_type, var/datum/event_source, var/datum/listener, var/proc_call) - var/decl/observ/event = GET_DECL(event_type) - if(event) - event.register(event_source, listener, proc_call) - -/repository/events/proc/unregister(var/event_type, var/datum/event_source, var/datum/listener, var/proc_call) - var/decl/observ/event = GET_DECL(event_type) - if(event) - event.unregister(event_source, listener, proc_call) - -/repository/events/proc/register_global(var/event_type, var/datum/listener, var/proc_call) - var/decl/observ/event = GET_DECL(event_type) - if(event) - event.register_global(listener, proc_call) - -/repository/events/proc/unregister_global(var/event_type, var/datum/listener, var/proc_call) - var/decl/observ/event = GET_DECL(event_type) - if(event) - event.unregister_global(listener, proc_call) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 7b27e55cb47..df5e4470d03 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -49,8 +49,8 @@ idcard = new idcard_type(src) set_id_info(idcard) -/mob/living/silicon/SetName(pickedName as text) - real_name = pickedName +/mob/living/silicon/SetName(new_name as text) + real_name = new_name name = real_name ..() diff --git a/polaris.dme b/polaris.dme index 0a721026777..b84fec6fdf7 100644 --- a/polaris.dme +++ b/polaris.dme @@ -314,7 +314,6 @@ #include "code\datums\extensions\event_registration.dm" #include "code\datums\extensions\extensions.dm" #include "code\datums\extensions\label.dm" -#include "code\datums\extensions\state_machine.dm" #include "code\datums\game_masters\_common.dm" #include "code\datums\game_masters\default.dm" #include "code\datums\game_masters\other_game_masters.dm" @@ -389,7 +388,6 @@ #include "code\datums\repositories\cameras.dm" #include "code\datums\repositories\crew.dm" #include "code\datums\repositories\decls.dm" -#include "code\datums\repositories\events.dm" #include "code\datums\repositories\repository.dm" #include "code\datums\repositories\unique.dm" #include "code\datums\roundstats\_defines_local.dm"