diff --git a/code/controllers/Processes/alarm.dm b/code/controllers/Processes/alarm.dm
index ed948276f8..47f311efea 100644
--- a/code/controllers/Processes/alarm.dm
+++ b/code/controllers/Processes/alarm.dm
@@ -20,7 +20,8 @@ var/datum/controller/process/alarm/alarm_manager
alarm_manager = src
/datum/controller/process/alarm/doWork()
- for(var/datum/alarm_handler/AH in all_handlers)
+ for(last_object in all_handlers)
+ var/datum/alarm_handler/AH = last_object
AH.process()
SCHECK
diff --git a/code/controllers/Processes/chemistry.dm b/code/controllers/Processes/chemistry.dm
index 282dd61c9f..084de83e28 100644
--- a/code/controllers/Processes/chemistry.dm
+++ b/code/controllers/Processes/chemistry.dm
@@ -18,7 +18,8 @@ var/datum/controller/process/chemistry/chemistryProcess
stat(null, "[active_holders.len] reagent holder\s")
/datum/controller/process/chemistry/doWork()
- for(var/datum/reagents/holder in active_holders)
+ for(last_object in active_holders)
+ var/datum/reagents/holder = last_object
if(!holder.process_reactions())
active_holders -= holder
SCHECK
diff --git a/code/controllers/Processes/garbage.dm b/code/controllers/Processes/garbage.dm
index ce6842ac3b..2d56dde1a2 100644
--- a/code/controllers/Processes/garbage.dm
+++ b/code/controllers/Processes/garbage.dm
@@ -1,7 +1,7 @@
// The time a datum was destroyed by the GC, or null if it hasn't been
/datum/var/gcDestroyed
-#define GC_COLLECTIONS_PER_RUN 150
+#define GC_COLLECTIONS_PER_RUN 300
#define GC_COLLECTION_TIMEOUT (30 SECONDS)
#define GC_FORCE_DEL_PER_RUN 30
@@ -23,7 +23,7 @@ var/list/delayed_garbage = list()
/datum/controller/process/garbage_collector/setup()
name = "garbage"
- schedule_interval = 10 SECONDS
+ schedule_interval = 5 SECONDS
start_delay = 3
if(!garbage_collector)
@@ -47,30 +47,6 @@ world/loop_checks = 0
var/checkRemain = GC_COLLECTIONS_PER_RUN
var/remaining_force_dels = GC_FORCE_DEL_PER_RUN
- #ifdef GC_FINDREF
- var/list/searching = list()
- for(var/refID in destroyed) // Reference search - before all deletions and for all at once
- var/GCd_at_time = destroyed[refID]
- if(GCd_at_time > time_to_kill)
- break
- var/atom/A = locate(refID)
- if(A && A.gcDestroyed == GCd_at_time)
- searching += A
- if(searching.len >= checkRemain)
- break
-
- for(var/atom/A in searching)
- testing("GC: Searching references for [A] | [A.type]")
- if(A.loc != null)
- testing("GC: [A] | [A.type] is located in [A.loc] instead of null")
- if(A.contents.len)
- testing("GC: [A] | [A.type] has contents: [list2text(A.contents)]")
- if(searching.len)
- for(var/atom/D in world)
- LookForRefs(D, searching)
- for(var/datum/D)
- LookForRefs(D, searching)
- #endif
while(destroyed.len && --checkRemain >= 0)
if(remaining_force_dels <= 0)
diff --git a/code/controllers/Processes/inactivity.dm b/code/controllers/Processes/inactivity.dm
index f12c0d4e3c..26cc136ccc 100644
--- a/code/controllers/Processes/inactivity.dm
+++ b/code/controllers/Processes/inactivity.dm
@@ -4,7 +4,8 @@
/datum/controller/process/inactivity/doWork()
if(config.kick_inactive)
- for(var/client/C in clients)
+ for(last_object in clients)
+ var/client/C = last_object
if(!C.holder && C.is_afk(config.kick_inactive MINUTES))
if(!istype(C.mob, /mob/observer/dead))
log_access("AFK: [key_name(C)]")
diff --git a/code/controllers/Processes/machinery.dm b/code/controllers/Processes/machinery.dm
index d046974489..405615dc1f 100644
--- a/code/controllers/Processes/machinery.dm
+++ b/code/controllers/Processes/machinery.dm
@@ -18,7 +18,8 @@
machines = dd_sortedObjectList(machines)
/datum/controller/process/machinery/proc/internal_process_machinery()
- for(var/obj/machinery/M in machines)
+ for(last_object in machines)
+ var/obj/machinery/M = last_object
if(M && !M.gcDestroyed)
if(M.process() == PROCESS_KILL)
//M.inMachineList = 0 We don't use this debugging function
@@ -31,7 +32,8 @@
SCHECK
/datum/controller/process/machinery/proc/internal_process_power()
- for(var/datum/powernet/powerNetwork in powernets)
+ for(last_object in powernets)
+ var/datum/powernet/powerNetwork = last_object
if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed))
powerNetwork.reset()
SCHECK
@@ -41,13 +43,15 @@
/datum/controller/process/machinery/proc/internal_process_power_drain()
// Currently only used by powersinks. These items get priority processed before machinery
- for(var/obj/item/I in processing_power_items)
+ for(last_object in processing_power_items)
+ var/obj/item/I = last_object
if(!I.pwr_drain()) // 0 = Process Kill, remove from processing list.
processing_power_items.Remove(I)
SCHECK
/datum/controller/process/machinery/proc/internal_process_pipenets()
- for(var/datum/pipe_network/pipeNetwork in pipe_networks)
+ for(last_object in pipe_networks)
+ var/datum/pipe_network/pipeNetwork = last_object
if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed))
pipeNetwork.process()
SCHECK
diff --git a/code/controllers/Processes/scheduler.dm b/code/controllers/Processes/scheduler.dm
new file mode 100644
index 0000000000..fdbe55faed
--- /dev/null
+++ b/code/controllers/Processes/scheduler.dm
@@ -0,0 +1,133 @@
+/var/datum/controller/process/scheduler/scheduler
+
+/************
+* Scheduler *
+************/
+/datum/controller/process/scheduler
+ var/list/scheduled_tasks
+
+/datum/controller/process/scheduler/setup()
+ name = "scheduler"
+ schedule_interval = 3 SECONDS
+ scheduled_tasks = list()
+ scheduler = src
+
+/datum/controller/process/scheduler/doWork()
+ for(last_object in scheduled_tasks)
+ var/datum/scheduled_task/scheduled_task = last_object
+ try
+ if(world.time > scheduled_task.trigger_time)
+ unschedule(scheduled_task)
+ scheduled_task.pre_process()
+ scheduled_task.process()
+ scheduled_task.post_process()
+ catch(var/exception/e)
+ catchException(e, last_object)
+ SCHECK
+
+/datum/controller/process/scheduler/statProcess()
+ ..()
+ stat(null, "[scheduled_tasks.len] task\s")
+
+/datum/controller/process/scheduler/proc/schedule(var/datum/scheduled_task/st)
+ scheduled_tasks += st
+ destroyed_event.register(st, src, /datum/controller/process/scheduler/proc/unschedule)
+
+/datum/controller/process/scheduler/proc/unschedule(var/datum/scheduled_task/st)
+ if(st in scheduled_tasks)
+ scheduled_tasks -= st
+ destroyed_event.unregister(st, src)
+
+/**********
+* Helpers *
+**********/
+/proc/schedule_task_in(var/in_time, var/procedure, var/list/arguments = list())
+ return schedule_task(world.time + in_time, procedure, arguments)
+
+/proc/schedule_task_with_source_in(var/in_time, var/source, var/procedure, var/list/arguments = list())
+ return schedule_task_with_source(world.time + in_time, source, procedure, arguments)
+
+/proc/schedule_task(var/trigger_time, var/procedure, var/list/arguments)
+ var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/destroy_scheduled_task, list())
+ scheduler.schedule(st)
+ return st
+
+/proc/schedule_task_with_source(var/trigger_time, var/source, var/procedure, var/list/arguments)
+ var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/destroy_scheduled_task, list())
+ scheduler.schedule(st)
+ return st
+
+/proc/schedule_repeating_task(var/trigger_time, var/repeat_interval, var/procedure, var/list/arguments)
+ var/datum/scheduled_task/st = new/datum/scheduled_task(trigger_time, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
+ scheduler.schedule(st)
+ return st
+
+/proc/schedule_repeating_task_with_source(var/trigger_time, var/repeat_interval, var/source, var/procedure, var/list/arguments)
+ var/datum/scheduled_task/st = new/datum/scheduled_task/source(trigger_time, source, procedure, arguments, /proc/repeat_scheduled_task, list(repeat_interval))
+ scheduler.schedule(st)
+ return st
+
+/*************
+* Task Datum *
+*************/
+/datum/scheduled_task
+ var/trigger_time
+ var/procedure
+ var/list/arguments
+ var/task_after_process
+ var/list/task_after_process_args
+
+/datum/scheduled_task/New(var/trigger_time, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
+ ..()
+ src.trigger_time = trigger_time
+ src.procedure = procedure
+ src.arguments = arguments ? arguments : list()
+ src.task_after_process = task_after_process ? task_after_process : /proc/destroy_scheduled_task
+ src.task_after_process_args = istype(task_after_process_args) ? task_after_process_args : list()
+ task_after_process_args += src
+
+/datum/scheduled_task/Destroy()
+ procedure = null
+ arguments.Cut()
+ task_after_process = null
+ task_after_process_args.Cut()
+ return ..()
+
+/datum/scheduled_task/proc/pre_process()
+ task_triggered_event.raise_event(list(src))
+
+/datum/scheduled_task/proc/process()
+ if(procedure)
+ call(procedure)(arglist(arguments))
+
+/datum/scheduled_task/proc/post_process()
+ call(task_after_process)(arglist(task_after_process_args))
+
+// Resets the trigger time, has no effect if the task has already triggered
+/datum/scheduled_task/proc/trigger_task_in(var/trigger_in)
+ src.trigger_time = world.time + trigger_in
+
+/datum/scheduled_task/source
+ var/datum/source
+
+/datum/scheduled_task/source/New(var/trigger_time, var/datum/source, var/procedure, var/list/arguments, var/proc/task_after_process, var/list/task_after_process_args)
+ src.source = source
+ destroyed_event.register(src.source, src, /datum/scheduled_task/source/proc/source_destroyed)
+ ..(trigger_time, procedure, arguments, task_after_process, task_after_process_args)
+
+/datum/scheduled_task/source/Destroy()
+ source = null
+ return ..()
+
+/datum/scheduled_task/source/process()
+ call(source, procedure)(arglist(arguments))
+
+/datum/scheduled_task/source/proc/source_destroyed()
+ qdel(src)
+
+/proc/destroy_scheduled_task(var/datum/scheduled_task/st)
+ qdel(st)
+
+/proc/repeat_scheduled_task(var/trigger_delay, var/datum/scheduled_task/st)
+ st.trigger_time = world.time + trigger_delay
+ scheduler.schedule(st)
\ No newline at end of file
diff --git a/code/controllers/Processes/turf.dm b/code/controllers/Processes/turf.dm
index 3396774497..bfced8f93b 100644
--- a/code/controllers/Processes/turf.dm
+++ b/code/controllers/Processes/turf.dm
@@ -5,7 +5,8 @@ var/global/list/turf/processing_turfs = list()
schedule_interval = 20 // every 2 seconds
/datum/controller/process/turf/doWork()
- for(var/turf/T in processing_turfs)
+ for(last_object in processing_turfs)
+ var/turf/T = last_object
if(T.process() == PROCESS_KILL)
processing_turfs.Remove(T)
SCHECK
diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm
index 5263e1af79..682b0fb3d0 100644
--- a/code/controllers/master_controller.dm
+++ b/code/controllers/master_controller.dm
@@ -47,7 +47,8 @@ datum/controller/game_controller/proc/setup_objects()
admin_notice("Initializing objects", R_DEBUG)
sleep(-1)
for(var/atom/movable/object in world)
- object.initialize()
+ if(isnull(object.gcDestroyed))
+ object.initialize()
admin_notice("Initializing areas", R_DEBUG)
sleep(-1)
diff --git a/code/controllers/observer_listener/datum/observer.dm b/code/controllers/observer_listener/datum/observer.dm
deleted file mode 100644
index 61f6fbf180..0000000000
--- a/code/controllers/observer_listener/datum/observer.dm
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-#define OBSERVER_EVENT_DESTROY "OnDestroy"
-
-/datum
- var/list/observer_events
-
-/datum/Destroy()
- for(var/list/listeners in observer_events)
- listeners.Cut()
-
- return ..()
-
-/datum/proc/register(var/event, var/procOwner, var/proc_call)
- var/list/listeners = get_listener_list_from_event(event)
- listeners[procOwner] = proc_call
-
-/datum/proc/unregister(var/event, var/procOwner)
- var/list/listeners = get_listener_list_from_event(event)
- listeners -= procOwner
-
-/datum/proc/get_listener_list_from_event(var/observer_event)
- if(!observer_events) observer_events = list()
- var/list/listeners = observer_events[observer_event]
- if(!listeners)
- listeners = list()
- observer_events[observer_event] = listeners
- return listeners
-*/
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index 34082d12ba..aef0fd0ac2 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -28,7 +28,6 @@ var/global/datum/getrev/revdata = new()
world.log << branch
world.log << date
world.log << revision
- return
client/verb/showrevinfo()
set category = "OOC"
@@ -43,4 +42,3 @@ client/verb/showrevinfo()
src << revdata.revision
else
src << "Revision unknown"
- return
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 824b52a2fe..11d622b255 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -71,6 +71,7 @@
/datum/mind/New(var/key)
src.key = key
+ ..()
/datum/mind/proc/transfer_to(mob/living/new_character)
if(!istype(new_character))
diff --git a/code/datums/observation/_debug.dm b/code/datums/observation/_debug.dm
new file mode 100644
index 0000000000..2f882929cf
--- /dev/null
+++ b/code/datums/observation/_debug.dm
@@ -0,0 +1,11 @@
+/****************
+* Debug Support *
+****************/
+var/datum/all_observable_events/all_observable_events = new()
+
+/datum/all_observable_events
+ var/list/events
+
+/datum/all_observable_events/New()
+ events = list()
+ ..()
diff --git a/code/datums/observation/_defines.dm b/code/datums/observation/_defines.dm
new file mode 100644
index 0000000000..902d655870
--- /dev/null
+++ b/code/datums/observation/_defines.dm
@@ -0,0 +1 @@
+#define CANCEL_MOVE_EVENT -55
diff --git a/code/datums/observation/destroyed.dm b/code/datums/observation/destroyed.dm
new file mode 100644
index 0000000000..6a65300a25
--- /dev/null
+++ b/code/datums/observation/destroyed.dm
@@ -0,0 +1,15 @@
+// Observer Pattern Implementation: Destroyed
+// Registration type: /datum
+//
+// Raised when: A /datum instance is destroyed.
+//
+// Arguments that the called proc should expect:
+// /datum/destroyed_instance: The instance that was destroyed.
+var/decl/observ/destroyed/destroyed_event = new()
+
+/decl/observ/destroyed
+ name = "Destroyed"
+
+/datum/Destroy()
+ destroyed_event.raise_event(src)
+ . = ..()
diff --git a/code/datums/observation/dir_set.dm b/code/datums/observation/dir_set.dm
new file mode 100644
index 0000000000..1f4c8e251e
--- /dev/null
+++ b/code/datums/observation/dir_set.dm
@@ -0,0 +1,35 @@
+// Observer Pattern Implementation: Direction Set
+// Registration type: /atom
+//
+// Raised when: An /atom changes dir using the set_dir() proc.
+//
+// Arguments that the called proc should expect:
+// /atom/dir_changer: The instance that changed direction
+// /old_dir: The dir before the change.
+// /new_dir: The dir after the change.
+
+var/decl/observ/dir_set/dir_set_event = new()
+
+/decl/observ/dir_set
+ name = "Direction Set"
+ expected_type = /atom
+
+/decl/observ/dir_set/register(var/atom/dir_changer, var/datum/listener, var/proc_call)
+ . = ..()
+
+ // Listen to the parent if possible.
+ if(. && istype(dir_changer.loc, /atom/movable)) // We don't care about registering to turfs.
+ register(dir_changer.loc, dir_changer, /atom/proc/recursive_dir_set)
+
+/*********************
+* Direction Handling *
+*********************/
+
+/atom/movable/Entered(var/atom/movable/am, atom/old_loc)
+ . = ..()
+ if(. != CANCEL_MOVE_EVENT && dir_set_event.has_listeners(am))
+ dir_set_event.register(src, am, /atom/proc/recursive_dir_set)
+
+/atom/movable/Exited(var/atom/movable/am, atom/old_loc)
+ . = ..()
+ dir_set_event.unregister(src, am, /atom/proc/recursive_dir_set)
diff --git a/code/datums/observation/equipped.dm b/code/datums/observation/equipped.dm
new file mode 100644
index 0000000000..de07a74355
--- /dev/null
+++ b/code/datums/observation/equipped.dm
@@ -0,0 +1,38 @@
+// Observer Pattern Implementation: Equipped
+// Registration type: /mob
+//
+// Raised when: A mob equips an item.
+//
+// Arguments that the called proc should expect:
+// /mob/equipper: The mob that equipped the item.
+// /obj/item/item: The equipped item.
+// slot: The slot equipped to.
+var/decl/observ/mob_equipped/mob_equipped_event = new()
+
+/decl/observ/mob_equipped
+ name = "Mob Equipped"
+ expected_type = /mob
+
+// Observer Pattern Implementation: Equipped
+// Registration type: /obj/item
+//
+// Raised when: A mob equips an item.
+//
+// Arguments that the called proc should expect:
+// /obj/item/item: The equipped item.
+// /mob/equipper: The mob that equipped the item.
+// slot: The slot equipped to.
+var/decl/observ/item_equipped/item_equipped_event = new()
+
+/decl/observ/item_equipped
+ name = "Item Equipped"
+ expected_type = /obj/item
+
+/********************
+* Equipped Handling *
+********************/
+
+/obj/item/equipped(var/mob/user, var/slot)
+ . = ..()
+ mob_equipped_event.raise_event(user, src, slot)
+ item_equipped_event.raise_event(src, user, slot)
diff --git a/code/datums/observation/helpers.dm b/code/datums/observation/helpers.dm
new file mode 100644
index 0000000000..79ee8eb08d
--- /dev/null
+++ b/code/datums/observation/helpers.dm
@@ -0,0 +1,18 @@
+/atom/movable/proc/recursive_move(var/atom/movable/am, var/old_loc, var/new_loc)
+ moved_event.raise_event(src, old_loc, new_loc)
+
+/atom/movable/proc/move_to_destination(var/atom/movable/am, var/old_loc, var/new_loc)
+ var/turf/T = get_turf(new_loc)
+ if(T && T != loc)
+ forceMove(T)
+
+/atom/proc/recursive_dir_set(var/atom/a, var/old_dir, var/new_dir)
+ set_dir(new_dir)
+
+/proc/register_all_movement(var/event_source, var/listener)
+ moved_event.register(event_source, listener, /atom/movable/proc/recursive_move)
+ dir_set_event.register(event_source, listener, /atom/proc/recursive_dir_set)
+
+/proc/unregister_all_movement(var/event_source, var/listener)
+ moved_event.unregister(event_source, listener, /atom/movable/proc/recursive_move)
+ dir_set_event.unregister(event_source, listener, /atom/proc/recursive_dir_set)
diff --git a/code/datums/observation/logged_in.dm b/code/datums/observation/logged_in.dm
new file mode 100644
index 0000000000..311ff8acb6
--- /dev/null
+++ b/code/datums/observation/logged_in.dm
@@ -0,0 +1,21 @@
+// Observer Pattern Implementation: Logged in
+// Registration type: /mob
+//
+// Raised when: A mob logs in (not client)
+//
+// Arguments that the called proc should expect:
+// /mob/joiner: The mob that has logged in
+
+var/decl/observ/logged_in/logged_in_event = new()
+
+/decl/observ/logged_in
+ name = "Logged In"
+ expected_type = /mob
+
+/*****************
+* Login Handling *
+*****************/
+
+/mob/Login()
+ ..()
+ logged_in_event.raise_event(src)
diff --git a/code/datums/observation/moved.dm b/code/datums/observation/moved.dm
new file mode 100644
index 0000000000..86a6b793ac
--- /dev/null
+++ b/code/datums/observation/moved.dm
@@ -0,0 +1,52 @@
+// Observer Pattern Implementation: Moved
+// Registration type: /atom/movable
+//
+// Raised when: An /atom/movable instance has moved using Move() or forceMove().
+//
+// Arguments that the called proc should expect:
+// /atom/movable/moving_instance: The instance that moved
+// /atom/old_loc: The loc before the move.
+// /atom/new_loc: The loc after the move.
+
+var/decl/observ/moved/moved_event = new()
+
+/decl/observ/moved
+ name = "Moved"
+ expected_type = /atom/movable
+
+/decl/observ/moved/register(var/atom/movable/mover, var/datum/listener, var/proc_call)
+ . = ..()
+
+ // Listen to the parent if possible.
+ if(. && istype(mover.loc, expected_type))
+ register(mover.loc, mover, /atom/movable/proc/recursive_move)
+
+/********************
+* Movement Handling *
+********************/
+
+/atom/Entered(var/atom/movable/am, var/atom/old_loc)
+ . = ..()
+ moved_event.raise_event(am, old_loc, am.loc)
+
+/atom/movable/Entered(var/atom/movable/am, atom/old_loc)
+ . = ..()
+ if(moved_event.has_listeners(am))
+ moved_event.register(src, am, /atom/movable/proc/recursive_move)
+
+/atom/movable/Exited(var/atom/movable/am, atom/old_loc)
+ . = ..()
+ moved_event.unregister(src, am, /atom/movable/proc/recursive_move)
+
+// Entered() typically lifts the moved event, but in the case of null-space we'll have to handle it.
+/atom/movable/Move()
+ var/old_loc = loc
+ . = ..()
+ if(. && !loc)
+ moved_event.raise_event(src, old_loc, null)
+
+/atom/movable/forceMove(atom/destination)
+ var/old_loc = loc
+ . = ..()
+ if(. && !loc)
+ moved_event.raise_event(src, old_loc, null)
diff --git a/code/datums/observation/observation.dm b/code/datums/observation/observation.dm
new file mode 100644
index 0000000000..32a96871e6
--- /dev/null
+++ b/code/datums/observation/observation.dm
@@ -0,0 +1,238 @@
+//
+// Observer Pattern Implementation
+//
+// Implements a basic observer pattern with the following main procs:
+//
+// /decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call)
+// event_source: The instance which is generating events.
+// listener: The instance which may be listening to events by event_source
+// proc_call: Optional. The specific proc to call when the event is raised.
+//
+// Returns true if listener is listening for events by event_source, and proc_call supplied is either null or one of the proc that will be called when an event is raised.
+//
+// /decl/observ/proc/has_listeners(var/event_source)
+// event_source: The instance which is generating events.
+//
+// Returns true if the given event_source has any listeners at all, globally or to specific event sources.
+//
+// /decl/observ/proc/register(var/event_source, var/datum/listener, var/proc_call)
+// event_source: The instance you wish to receive events from.
+// listener: The instance/owner of the proc to call when an event is raised by the event_source.
+// proc_call: The proc to call when an event is raised.
+//
+// It is possible to register the same listener to the same event_source multiple times as long as it is using different proc_calls.
+// Registering again using the same event_source, listener, and proc_call that has been registered previously will have no additional effect.
+// I.e.: The proc_call will still only be called once per raised event. That particular proc_call will only have to be unregistered once.
+//
+// When proc_call is called the first argument is always the source of the event (event_source).
+// Additional arguments may or may not be supplied, see individual event definition files (destroyed.dm, moved.dm, etc.) for details.
+//
+// The instance making the register() call is also responsible for calling unregister(), see below for additonal details, including when event_source is destroyed.
+// This can be handled by listening to the event_source's destroyed event, unregistering in the listener's Destroy() proc, etc.
+//
+// /decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call)
+// event_source: The instance you wish to stop receiving events from.
+// listener: The instance which will no longer receive the events.
+// proc_call: Optional: The proc_call to unregister.
+//
+// Unregisters the listener from the event_source.
+// If a proc_call has been supplied only that particular proc_call will be unregistered. If the proc_call isn't currently registered there will be no effect.
+// If no proc_call has been supplied, the listener will have all registrations made to the given event_source undone.
+//
+// /decl/observ/proc/register_global(var/datum/listener, var/proc_call)
+// listener: The instance/owner of the proc to call when an event is raised by any and all sources.
+// proc_call: The proc to call when an event is raised.
+//
+// Works very much the same as register(), only the listener/proc_call will receive all relevant events from all event sources.
+// Global registrations can overlap with registrations made to specific event sources and these will not affect each other.
+//
+// /decl/observ/proc/unregister_global(var/datum/listener, var/proc_call)
+// listener: The instance/owner of the proc which will no longer receive the events.
+// proc_call: Optional: The proc_call to unregister.
+//
+// Works very much the same as unregister(), only it undoes global registrations instead.
+//
+// /decl/observ/proc/raise_event(src, ...)
+// Should never be called unless implementing a new event type.
+// The first argument shall always be the event_source belonging to the event. Beyond that there are no restrictions.
+
+/decl/observ
+ var/name = "Unnamed Event" // The name of this event, used mainly for debug/VV purposes. The list of event managers can be reached through the "Debug Controller" verb, selecting the "Observation" entry.
+ var/expected_type = /datum // The expected event source for this event. register() will CRASH() if it receives an unexpected type.
+ var/list/event_sources = list() // Associative list of event sources, each with their own associative list. This associative list contains an instance/list of procs to call when the event is raised.
+ var/list/global_listeners = list() // Associative list of instances that listen to all events of this type (as opposed to events belonging to a specific source) and the proc to call.
+
+/decl/observ/New()
+ all_observable_events.events += src
+ . = ..()
+
+/decl/observ/proc/is_listening(var/event_source, var/datum/listener, var/proc_call)
+ // Return whether there are global listeners unless the event source is given.
+ if (!event_source)
+ return !!global_listeners.len
+
+ // Return whether anything is listening to a source, if no listener is given.
+ if (!listener)
+ return global_listeners.len || (event_source in event_sources)
+
+ // Return false if nothing is associated with that source.
+ if (!(event_source in event_sources))
+ return FALSE
+
+ // Get and check the listeners for the reuqested event.
+ var/listeners = event_sources[event_source]
+ if (!(listener in listeners))
+ return FALSE
+
+ // Return true unless a specific callback needs checked.
+ if (!proc_call)
+ return TRUE
+
+ // Check if the specific callback exists.
+ var/list/callback = listeners[listener]
+ if (!callback)
+ return FALSE
+
+ return (proc_call in callback)
+
+/decl/observ/proc/has_listeners(var/event_source)
+ return is_listening(event_source)
+
+/decl/observ/proc/register(var/datum/event_source, var/datum/listener, var/proc_call)
+ // Sanity checking.
+ if (!(event_source && listener && proc_call))
+ return FALSE
+ if (istype(event_source, /decl/observ))
+ return FALSE
+
+ // Crash if the event source is the wrong type.
+ if (!istype(event_source, expected_type))
+ CRASH("Unexpected type. Expected [expected_type], was [event_source.type]")
+
+ // Setup the listeners for this source if needed.
+ var/list/listeners = event_sources[event_source]
+ if (!listeners)
+ listeners = list()
+ event_sources[event_source] = listeners
+
+ // Make sure the callbacks are a list.
+ var/list/callbacks = listeners[listener]
+ if (!callbacks)
+ callbacks = list()
+ listeners[listener] = callbacks
+
+ // If the proc_call is already registered skip
+ if(proc_call in callbacks)
+ return FALSE
+
+ // Add the callback, and return true.
+ callbacks += proc_call
+ return TRUE
+
+/decl/observ/proc/unregister(var/event_source, var/datum/listener, var/proc_call)
+ // Sanity.
+ if (!(event_source && listener && (event_source in event_sources)))
+ return FALSE
+
+ // Return false if nothing is listening for this event.
+ var/list/listeners = event_sources[event_source]
+ if (!listeners)
+ return FALSE
+
+ // Remove all callbacks if no specific one is given.
+ if (!proc_call)
+ if(listeners.Remove(listener))
+ // Perform some cleanup and return true.
+ if (!listeners.len)
+ event_sources -= event_source
+ return TRUE
+ return FALSE
+
+ // See if the listener is registered.
+ var/list/callbacks = listeners[listener]
+ if (!callbacks)
+ return FALSE
+
+ // See if the callback exists.
+ if(!callbacks.Remove(proc_call))
+ return FALSE
+
+ if (!callbacks.len)
+ listeners -= listener
+ if (!listeners.len)
+ event_sources -= event_source
+ return TRUE
+
+/decl/observ/proc/register_global(var/datum/listener, var/proc_call)
+ // Sanity.
+ if (!(listener && proc_call))
+ return FALSE
+
+ // Make sure the callbacks are setup.
+ var/list/callbacks = global_listeners[listener]
+ if (!callbacks)
+ callbacks = list()
+ global_listeners[listener] = callbacks
+
+ // Add the callback and return true.
+ callbacks |= proc_call
+ return TRUE
+
+/decl/observ/proc/unregister_global(var/datum/listener, var/proc_call)
+ // Return false unless the listener is set as a global listener.
+ if (!(listener && (listener in global_listeners)))
+ return FALSE
+
+ // Remove all callbacks if no specific one is given.
+ if (!proc_call)
+ global_listeners -= listener
+ return TRUE
+
+ // See if the listener is registered.
+ var/list/callbacks = global_listeners[listener]
+ if (!callbacks)
+ return FALSE
+
+ // See if the callback exists.
+ if(!callbacks.Remove(proc_call))
+ return FALSE
+
+ if (!callbacks.len)
+ global_listeners -= listener
+ return TRUE
+
+/decl/observ/proc/raise_event()
+ // Sanity
+ if (!args.len)
+ return FALSE
+
+ // Call the global listeners.
+ for (var/datum/listener in global_listeners)
+ var/list/callbacks = global_listeners[listener]
+ for (var/proc_call in callbacks)
+
+ // If the callback crashes, record the error and remove it.
+ try
+ call(listener, proc_call)(arglist(args))
+ catch (var/exception/e)
+ error("[e.name] - [e.file] - [e.line]")
+ error(e.desc)
+ unregister_global(listener, proc_call)
+
+ // Call the listeners for this specific event source, if they exist.
+ var/source = args[1]
+ if (source in event_sources)
+ var/list/listeners = event_sources[source]
+ for (var/datum/listener in listeners)
+ var/list/callbacks = listeners[listener]
+ for (var/proc_call in callbacks)
+
+ // If the callback crashes, record the error and remove it.
+ try
+ call(listener, proc_call)(arglist(args))
+ catch (var/exception/e)
+ error("[e.name] - [e.file] - [e.line]")
+ error(e.desc)
+ unregister(source, listener, proc_call)
+
+ return TRUE
diff --git a/code/datums/observation/task_triggered.dm b/code/datums/observation/task_triggered.dm
new file mode 100644
index 0000000000..0c04ef2ead
--- /dev/null
+++ b/code/datums/observation/task_triggered.dm
@@ -0,0 +1,13 @@
+//
+// Observer Pattern Implementation: Scheduled task triggered
+// Registration type: /datum/scheduled_task
+//
+// Raised when: When a scheduled task reaches its trigger time.
+//
+// Arguments that the called proc should expect:
+// /datum/scheduled_task/task: The task that reached its trigger time.
+var/decl/observ/task_triggered/task_triggered_event = new()
+
+/decl/observ/task_triggered
+ name = "Task Triggered"
+ expected_type = /datum/scheduled_task
diff --git a/code/datums/observation/unequipped.dm b/code/datums/observation/unequipped.dm
new file mode 100644
index 0000000000..3287c0a3b5
--- /dev/null
+++ b/code/datums/observation/unequipped.dm
@@ -0,0 +1,38 @@
+// Observer Pattern Implementation: Unequipped (dropped)
+// Registration type: /mob
+//
+// Raised when: A mob unequips/drops an item.
+//
+// Arguments that the called proc should expect:
+// /mob/equipped: The mob that unequipped/dropped the item.
+// /obj/item/item: The unequipped item.
+
+var/decl/observ/mob_unequipped/mob_unequipped_event = new()
+
+/decl/observ/mob_unequipped
+ name = "Mob Unequipped"
+ expected_type = /mob
+
+// Observer Pattern Implementation: Unequipped (dropped)
+// Registration type: /obj/item
+//
+// Raised when: A mob unequips/drops an item.
+//
+// Arguments that the called proc should expect:
+// /obj/item/item: The unequipped item.
+// /mob/equipped: The mob that unequipped/dropped the item.
+
+var/decl/observ/item_unequipped/item_unequipped_event = new()
+
+/decl/observ/item_unequipped
+ name = "Item Unequipped"
+ expected_type = /obj/item
+
+/**********************
+* Unequipped Handling *
+**********************/
+
+/obj/item/dropped(var/mob/user)
+ ..()
+ mob_unequipped_event.raise_event(user, src)
+ item_unequipped_event.raise_event(src, user)
diff --git a/code/datums/observation/~cleanup.dm b/code/datums/observation/~cleanup.dm
new file mode 100644
index 0000000000..eb6ccceef8
--- /dev/null
+++ b/code/datums/observation/~cleanup.dm
@@ -0,0 +1,70 @@
+var/list/global_listen_count = list()
+var/list/event_sources_count = list()
+var/list/event_listen_count = list()
+
+/decl/observ/destroyed/raise_event()
+ . = ..()
+ if(!.)
+ return
+ var/source = args[1]
+
+ if(global_listen_count[source])
+ cleanup_global_listener(source, global_listen_count[source])
+ if(event_sources_count[source])
+ cleanup_source_listeners(source, event_sources_count[source])
+ if(event_listen_count[source])
+ cleanup_event_listener(source, event_listen_count[source])
+
+
+/decl/observ/register(var/datum/event_source, var/datum/listener, var/proc_call)
+ . = ..()
+ if(.)
+ event_sources_count[event_source] += 1
+ event_listen_count[listener] += 1
+
+/decl/observ/unregister(var/datum/event_source, var/datum/listener, var/proc_call)
+ . = ..()
+ if(.)
+ event_sources_count[event_source] -= 1
+ event_listen_count[listener] -= 1
+
+/decl/observ/register_global(var/datum/listener, var/proc_call)
+ . = ..()
+ if(.)
+ global_listen_count[listener] += 1
+
+/decl/observ/unregister_global(var/datum/listener, var/proc_call)
+ . = ..()
+ if(.)
+ global_listen_count[listener] -= 1
+
+/decl/observ/destroyed/proc/cleanup_global_listener(listener, listen_count)
+ global_listen_count -= listener
+ for(var/entry in all_observable_events.events)
+ var/decl/observ/event = entry
+ if(event.unregister_global(listener))
+ log_debug("[event] - [listener] was deleted while still registered to global events.")
+ if(!(--listen_count))
+ return
+
+/decl/observ/destroyed/proc/cleanup_source_listeners(event_source, source_listener_count)
+ event_sources_count -= event_source
+ for(var/entry in all_observable_events.events)
+ var/decl/observ/event = entry
+ var/proc_owners = event.event_sources[event_source]
+ if(proc_owners)
+ for(var/proc_owner in proc_owners)
+ if(event.unregister(event_source, proc_owner))
+ log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].")
+ if(!(--source_listener_count))
+ return
+
+/decl/observ/destroyed/proc/cleanup_event_listener(listener, listener_count)
+ event_listen_count -= listener
+ for(var/entry in all_observable_events.events)
+ var/decl/observ/event = entry
+ for(var/event_source in event.event_sources)
+ if(event.unregister(event_source, listener))
+ log_debug("[event] - [listener] was deleted while still listening to [event_source].")
+ if(!(--listener_count))
+ return
diff --git a/code/defines/obj/weapon.dm b/code/defines/obj/weapon.dm
index 39c91afbed..77779bafcf 100644
--- a/code/defines/obj/weapon.dm
+++ b/code/defines/obj/weapon.dm
@@ -44,6 +44,7 @@
/obj/item/weapon/soap/deluxe/New()
desc = "A deluxe Waffle Co. brand bar of soap. Smells of [pick("lavender", "vanilla", "strawberry", "chocolate" ,"space")]."
+ ..()
/obj/item/weapon/soap/syndie
desc = "An untrustworthy bar of soap. Smells of fear."
@@ -398,9 +399,11 @@
icon = 'icons/obj/stock_parts.dmi'
w_class = 2.0
var/rating = 1
- New()
- src.pixel_x = rand(-5.0, 5)
- src.pixel_y = rand(-5.0, 5)
+
+/obj/item/weapon/stock_parts/New()
+ src.pixel_x = rand(-5.0, 5)
+ src.pixel_y = rand(-5.0, 5)
+ ..()
//Rank 1
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index 7639084918..e45be4bb6a 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -46,7 +46,8 @@
pulledby = null
/atom/movable/proc/initialize()
- return
+ if(!isnull(gcDestroyed))
+ crash_with("GC: -- [type] had initialize() called after qdel() --")
/atom/movable/Bump(var/atom/A, yes)
if(src.throwing)
@@ -211,7 +212,7 @@
/atom/movable/overlay/New()
for(var/x in src.verbs)
src.verbs -= x
- return
+ ..()
/atom/movable/overlay/attackby(a, b)
if (src.master)
diff --git a/code/game/gamemodes/events/dust.dm b/code/game/gamemodes/events/dust.dm
index 492b932e46..bb8e34364c 100644
--- a/code/game/gamemodes/events/dust.dm
+++ b/code/game/gamemodes/events/dust.dm
@@ -53,6 +53,7 @@ The "dust" will damage the hull of the station causin minor hull breaches.
New()
+ ..()
var/startx = 0
var/starty = 0
var/endy = 0
diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm
index 6b373953b1..f5dd1efe5f 100644
--- a/code/game/gamemodes/objective.dm
+++ b/code/game/gamemodes/objective.dm
@@ -12,6 +12,7 @@ datum/objective
all_objectives |= src
if(text)
explanation_text = text
+ ..()
Destroy()
all_objectives -= src
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index eed2d4d031..25b38e3b20 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -424,6 +424,7 @@
read_only = 1
New()
+ ..()
initializeDisk()
buf.types=DNA2_BUF_SE
var/list/new_SE=list(0x098,0x3E8,0x403,0x44C,0x39F,0x4B0,0x59D,0x514,0x5FC,0x578,0x5DC,0x640,0x6A4)
diff --git a/code/game/machinery/computer/atmos_alert.dm b/code/game/machinery/computer/atmos_alert.dm
index f4b06aff1c..eef148a830 100644
--- a/code/game/machinery/computer/atmos_alert.dm
+++ b/code/game/machinery/computer/atmos_alert.dm
@@ -14,10 +14,10 @@ var/global/list/minor_air_alarms = list()
/obj/machinery/computer/atmos_alert/New()
..()
- atmosphere_alarm.register(src, /obj/machinery/computer/station_alert/update_icon)
+ atmosphere_alarm.register_alarm(src, /obj/machinery/computer/station_alert/update_icon)
/obj/machinery/computer/atmos_alert/Destroy()
- atmosphere_alarm.unregister(src)
+ atmosphere_alarm.unregister_alarm(src)
..()
/obj/machinery/computer/atmos_alert/attack_hand(mob/user)
diff --git a/code/game/machinery/computer/camera_circuit.dm b/code/game/machinery/computer/camera_circuit.dm
index 4680bb57d1..8db87c36ae 100644
--- a/code/game/machinery/computer/camera_circuit.dm
+++ b/code/game/machinery/computer/camera_circuit.dm
@@ -17,6 +17,7 @@
possibleNets["Cargo"] = access_qm
possibleNets["Research"] = access_rd
possibleNets["Medbay"] = access_cmo
+ ..()
proc/updateBuildPath()
build_path = null
diff --git a/code/game/machinery/computer/station_alert.dm b/code/game/machinery/computer/station_alert.dm
index 22c97a955a..d1c66b500d 100644
--- a/code/game/machinery/computer/station_alert.dm
+++ b/code/game/machinery/computer/station_alert.dm
@@ -17,13 +17,13 @@
monitor_type = /datum/nano_module/alarm_monitor/all
circuit = /obj/item/weapon/circuitboard/stationalert_all
-/obj/machinery/computer/station_alert/New()
- ..()
+/obj/machinery/computer/station_alert/initialize()
alarm_monitor = new monitor_type(src)
- alarm_monitor.register(src, /obj/machinery/computer/station_alert/update_icon)
+ alarm_monitor.register_alarm(src, /obj/machinery/computer/station_alert/update_icon)
+ ..()
/obj/machinery/computer/station_alert/Destroy()
- alarm_monitor.unregister(src)
+ alarm_monitor.unregister_alarm(src)
qdel(alarm_monitor)
..()
@@ -46,7 +46,7 @@
/obj/machinery/computer/station_alert/update_icon()
if(!(stat & (BROKEN|NOPOWER)))
- var/list/alarms = alarm_monitor.major_alarms()
+ var/list/alarms = alarm_monitor ? alarm_monitor.major_alarms() : list()
if(alarms.len)
icon_screen = "alert:2"
else
diff --git a/code/game/machinery/computer3/file.dm b/code/game/machinery/computer3/file.dm
index b1fbe0ddbe..be4285b3e1 100644
--- a/code/game/machinery/computer3/file.dm
+++ b/code/game/machinery/computer3/file.dm
@@ -100,6 +100,7 @@
if(content)
if(file_increment > 1)
volume = round(file_increment * length(content))
+ ..()
/*
A generic file that contains text
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index 3681d1e798..30a9b8548b 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -136,7 +136,7 @@ Class Procs:
if(contents) // The same for contents.
for(var/atom/A in contents)
qdel(A)
- ..()
+ return ..()
/obj/machinery/process()//If you dont use process or power why are you here
if(!(use_power || idle_power_usage || active_power_usage))
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index 01fc592690..8b349959b5 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -107,9 +107,6 @@ steam.start() -- spawns the effect
var/turf/T = src.loc
if (istype(T, /turf))
T.hotspot_expose(1000,100)
- spawn (20)
- qdel(src)
- return
/obj/effect/effect/sparks/Destroy()
var/turf/T = src.loc
@@ -185,7 +182,6 @@ steam.start() -- spawns the effect
..()
spawn (time_to_live)
qdel(src)
- return
/obj/effect/effect/smoke/Crossed(mob/living/carbon/M as mob )
..()
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 15cb670a8c..d08d45d5ce 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -5,6 +5,7 @@
anchored = 1.0
unacidable = 1
simulated = 0
+ var/delete_me = 0
/obj/effect/landmark/New()
..()
@@ -14,33 +15,35 @@
switch(name) //some of these are probably obsolete
if("monkey")
monkeystart += loc
- qdel(src)
+ delete_me = 1
return
if("start")
newplayer_start += loc
- qdel(src)
+ delete_me = 1
+ return
if("JoinLate")
latejoin += loc
- qdel(src)
+ delete_me = 1
+ return
if("JoinLateGateway")
latejoin_gateway += loc
- qdel(src)
+ delete_me = 1
return
if("JoinLateElevator")
latejoin_elevator += loc
- qdel(src)
+ delete_me = 1
return
if("JoinLateCryo")
latejoin_cryo += loc
- qdel(src)
+ delete_me = 1
return
if("JoinLateCyborg")
latejoin_cyborg += loc
- qdel(src)
+ delete_me = 1
return
if("prisonwarp")
prisonwarp += loc
- qdel(src)
+ delete_me = 1
return
if("Holding Facility")
holdingfacility += loc
@@ -54,28 +57,36 @@
tdomeobserve += loc
if("prisonsecuritywarp")
prisonsecuritywarp += loc
- qdel(src)
+ delete_me = 1
return
if("blobstart")
blobstart += loc
- qdel(src)
+ delete_me = 1
return
if("xeno_spawn")
xeno_spawn += loc
- qdel(src)
+ delete_me = 1
return
if("endgame_exit")
endgame_safespawns += loc
- qdel(src)
+ delete_me = 1
return
if("bluespacerift")
endgame_exits += loc
- qdel(src)
+ delete_me = 1
return
landmarks_list += src
return 1
+/obj/effect/landmark/proc/delete()
+ delete_me = 1
+
+/obj/effect/landmark/initialize()
+ ..()
+ if(delete_me)
+ qdel(src)
+
/obj/effect/landmark/Destroy()
landmarks_list -= src
return ..()
@@ -99,14 +110,14 @@
var/list/options = typesof(/obj/effect/landmark/costume)
var/PICK= options[rand(1,options.len)]
new PICK(src.loc)
- qdel(src)
+ delete_me = 1
//SUBCLASSES. Spawn a bunch of items and disappear likewise
/obj/effect/landmark/costume/chicken/New()
new /obj/item/clothing/suit/chickensuit(src.loc)
new /obj/item/clothing/head/chicken(src.loc)
new /obj/item/weapon/reagent_containers/food/snacks/egg(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/gladiator/New()
new /obj/item/clothing/under/gladiator(src.loc)
@@ -118,32 +129,32 @@
new /obj/item/clothing/head/flatcap(src.loc)
new /obj/item/clothing/suit/storage/toggle/labcoat/mad(src.loc)
new /obj/item/clothing/glasses/gglasses(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/elpresidente/New()
new /obj/item/clothing/under/gimmick/rank/captain/suit(src.loc)
new /obj/item/clothing/head/flatcap(src.loc)
new /obj/item/clothing/mask/smokable/cigarette/cigar/havana(src.loc)
new /obj/item/clothing/shoes/jackboots(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/nyangirl/New()
new /obj/item/clothing/under/schoolgirl(src.loc)
new /obj/item/clothing/head/kitty(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/maid/New()
new /obj/item/clothing/under/skirt(src.loc)
var/CHOICE = pick( /obj/item/clothing/head/beret , /obj/item/clothing/head/rabbitears )
new CHOICE(src.loc)
new /obj/item/clothing/glasses/sunglasses/blindfold(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/butler/New()
new /obj/item/clothing/suit/wcoat(src.loc)
new /obj/item/clothing/under/suit_jacket(src.loc)
new /obj/item/clothing/head/that(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/scratch/New()
new /obj/item/clothing/gloves/white(src.loc)
@@ -151,12 +162,12 @@
new /obj/item/clothing/under/scratch(src.loc)
if (prob(30))
new /obj/item/clothing/head/cueball(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/highlander/New()
new /obj/item/clothing/under/kilt(src.loc)
new /obj/item/clothing/head/beret(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/prig/New()
new /obj/item/clothing/suit/wcoat(src.loc)
@@ -167,24 +178,24 @@
new /obj/item/weapon/cane(src.loc)
new /obj/item/clothing/under/sl_suit(src.loc)
new /obj/item/clothing/mask/fakemoustache(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/plaguedoctor/New()
new /obj/item/clothing/suit/bio_suit/plaguedoctorsuit(src.loc)
new /obj/item/clothing/head/plaguedoctorhat(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/nightowl/New()
new /obj/item/clothing/under/owl(src.loc)
new /obj/item/clothing/mask/gas/owl_mask(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/waiter/New()
new /obj/item/clothing/under/waiter(src.loc)
var/CHOICE= pick( /obj/item/clothing/head/kitty, /obj/item/clothing/head/rabbitears)
new CHOICE(src.loc)
new /obj/item/clothing/suit/apron(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/pirate/New()
new /obj/item/clothing/under/pirate(src.loc)
@@ -192,18 +203,18 @@
var/CHOICE = pick( /obj/item/clothing/head/pirate , /obj/item/clothing/head/bandana )
new CHOICE(src.loc)
new /obj/item/clothing/glasses/eyepatch(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/commie/New()
new /obj/item/clothing/under/soviet(src.loc)
new /obj/item/clothing/head/ushanka(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/imperium_monk/New()
new /obj/item/clothing/suit/imperium_monk(src.loc)
if (prob(25))
new /obj/item/clothing/mask/gas/cyborg(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/holiday_priest/New()
new /obj/item/clothing/suit/holidaypriest(src.loc)
@@ -212,26 +223,26 @@
/obj/effect/landmark/costume/marisawizard/fake/New()
new /obj/item/clothing/head/wizard/marisa/fake(src.loc)
new/obj/item/clothing/suit/wizrobe/marisa/fake(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/cutewitch/New()
new /obj/item/clothing/under/sundress(src.loc)
new /obj/item/clothing/head/witchwig(src.loc)
new /obj/item/weapon/staff/broom(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/fakewizard/New()
new /obj/item/clothing/suit/wizrobe/fake(src.loc)
new /obj/item/clothing/head/wizard/fake(src.loc)
new /obj/item/weapon/staff/(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/sexyclown/New()
new /obj/item/clothing/mask/gas/sexyclown(src.loc)
new /obj/item/clothing/under/sexyclown(src.loc)
- qdel(src)
+ delete_me = 1
/obj/effect/landmark/costume/sexymime/New()
new /obj/item/clothing/mask/gas/sexymime(src.loc)
new /obj/item/clothing/under/sexymime(src.loc)
- qdel(src)
\ No newline at end of file
+ delete_me = 1
diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm
index 9a54fa1829..9b5dffdd37 100644
--- a/code/game/objects/items/devices/radio/encryptionkey.dm
+++ b/code/game/objects/items/devices/radio/encryptionkey.dm
@@ -12,9 +12,6 @@
var/syndie = 0
var/list/channels = list()
-
-/obj/item/device/encryptionkey/New()
-
/obj/item/device/encryptionkey/attackby(obj/item/weapon/W as obj, mob/user as mob)
/obj/item/device/encryptionkey/syndicate
diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm
index e2ec23be7c..2a85fbdfc9 100644
--- a/code/game/objects/items/weapons/extinguisher.dm
+++ b/code/game/objects/items/weapons/extinguisher.dm
@@ -37,6 +37,7 @@
/obj/item/weapon/extinguisher/New()
create_reagents(max_water)
reagents.add_reagent("water", max_water)
+ ..()
/obj/item/weapon/extinguisher/examine(mob/user)
if(..(user, 0))
diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm
index b39fc0dd27..b7868cf7e0 100644
--- a/code/game/objects/items/weapons/tools.dm
+++ b/code/game/objects/items/weapons/tools.dm
@@ -79,7 +79,7 @@
if (prob(75))
src.pixel_y = rand(0, 16)
- return
+ ..()
/obj/item/weapon/screwdriver/attack(mob/living/carbon/M as mob, mob/living/carbon/user as mob)
if(!istype(M) || user.a_intent == "help")
@@ -114,6 +114,7 @@
if(prob(50))
icon_state = "cutters-y"
item_state = "cutters_yellow"
+ ..()
/obj/item/weapon/wirecutters/attack(mob/living/carbon/C as mob, mob/user as mob)
if(user.a_intent == I_HELP && (C.handcuffed) && (istype(C.handcuffed, /obj/item/weapon/handcuffs/cable)))
@@ -162,12 +163,12 @@
reagents = R
R.my_atom = src
R.add_reagent("fuel", max_fuel)
- return
+ ..()
/obj/item/weapon/weldingtool/Destroy()
if(welding)
processing_objects -= src
- ..()
+ return ..()
/obj/item/weapon/weldingtool/examine(mob/user)
if(..(user, 0))
diff --git a/code/game/objects/random/random.dm b/code/game/objects/random/random.dm
index 1127bf7510..fc6615fcf0 100644
--- a/code/game/objects/random/random.dm
+++ b/code/game/objects/random/random.dm
@@ -11,8 +11,10 @@
..()
if (!prob(spawn_nothing_percentage))
spawn_item()
- qdel(src)
+/obj/random/initialize()
+ ..()
+ qdel(src)
// this function should return a specific item to spawn
/obj/random/proc/item_to_spawn()
diff --git a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
index 31f8115b91..714be281b8 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -22,7 +22,7 @@
/obj/structure/closet/emcloset/New()
..()
- switch (pickweight(list("small" = 55, "aid" = 25, "tank" = 10, "both" = 10, "nothing" = 0, "delete" = 0)))
+ switch (pickweight(list("small" = 55, "aid" = 25, "tank" = 10, "both" = 10)))
if ("small")
new /obj/item/weapon/tank/emergency_oxygen(src)
new /obj/item/weapon/tank/emergency_oxygen(src)
@@ -51,17 +51,6 @@
new /obj/item/clothing/suit/space/emergency(src)
new /obj/item/clothing/head/helmet/space/emergency(src)
new /obj/item/clothing/head/helmet/space/emergency(src)
- if ("nothing")
- // doot
-
- // teehee - Ah, tg coders...
- if ("delete")
- qdel(src)
-
- //If you want to re-add fire, just add "fire" = 15 to the pick list.
- /*if ("fire")
- new /obj/structure/closet/firecloset(src.loc)
- qdel(src)*/
/obj/structure/closet/emcloset/legacy/New()
..()
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index 2b8396c554..eff0de4b48 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -9,7 +9,7 @@
layer = 2.3 //under pipes
// flags = CONDUCT
-/obj/structure/lattice/New() //turf/simulated/floor/asteroid
+/obj/structure/lattice/initialize()
..()
if(!(istype(src.loc, /turf/space) || istype(src.loc, /turf/simulated/open) || istype(src.loc, /turf/simulated/mineral)))
diff --git a/code/game/objects/structures/mop_bucket.dm b/code/game/objects/structures/mop_bucket.dm
index 1624a4bbde..c76ca1802d 100644
--- a/code/game/objects/structures/mop_bucket.dm
+++ b/code/game/objects/structures/mop_bucket.dm
@@ -12,7 +12,7 @@
/obj/structure/mopbucket/New()
create_reagents(100)
-
+ ..()
/obj/structure/mopbucket/examine(mob/user)
if(..(user, 1))
diff --git a/code/modules/alarm/alarm_handler.dm b/code/modules/alarm/alarm_handler.dm
index 47b7f7b571..afa45d7649 100644
--- a/code/modules/alarm/alarm_handler.dm
+++ b/code/modules/alarm/alarm_handler.dm
@@ -86,10 +86,10 @@
/turf/get_alarm_origin()
return get_area(src)
-/datum/alarm_handler/proc/register(var/object, var/procName)
+/datum/alarm_handler/proc/register_alarm(var/object, var/procName)
listeners[object] = procName
-/datum/alarm_handler/proc/unregister(var/object)
+/datum/alarm_handler/proc/unregister_alarm(var/object)
listeners -= object
/datum/alarm_handler/proc/notify_listeners(var/alarm, var/was_raised)
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index d670e17ee3..5a13c7bb79 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -40,7 +40,7 @@
/mob/living/silicon/Destroy()
silicon_mob_list -= src
for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
- AH.unregister(src)
+ AH.unregister_alarm(src)
..()
/mob/living/silicon/proc/init_id()
diff --git a/code/modules/mob/living/silicon/subystems.dm b/code/modules/mob/living/silicon/subystems.dm
index fa1363203b..1dae0026aa 100644
--- a/code/modules/mob/living/silicon/subystems.dm
+++ b/code/modules/mob/living/silicon/subystems.dm
@@ -39,7 +39,7 @@
return
for(var/datum/alarm_handler/AH in alarm_manager.all_handlers)
- AH.register(src, /mob/living/silicon/proc/receive_alarm)
+ AH.register_alarm(src, /mob/living/silicon/proc/receive_alarm)
queued_alarms[AH] = list() // Makes sure alarms remain listed in consistent order
/********************
diff --git a/code/modules/nano/modules/alarm_monitor.dm b/code/modules/nano/modules/alarm_monitor.dm
index 29ae55b04a..f3fca46d43 100644
--- a/code/modules/nano/modules/alarm_monitor.dm
+++ b/code/modules/nano/modules/alarm_monitor.dm
@@ -15,13 +15,13 @@
..()
alarm_handlers = list(camera_alarm, motion_alarm)
-/datum/nano_module/alarm_monitor/proc/register(var/object, var/procName)
+/datum/nano_module/alarm_monitor/proc/register_alarm(var/object, var/procName)
for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.register(object, procName)
+ AH.register_alarm(object, procName)
-/datum/nano_module/alarm_monitor/proc/unregister(var/object)
+/datum/nano_module/alarm_monitor/proc/unregister_alarm(var/object)
for(var/datum/alarm_handler/AH in alarm_handlers)
- AH.unregister(object)
+ AH.unregister_alarm(object)
/datum/nano_module/alarm_monitor/proc/all_alarms()
var/list/all_alarms = new()
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index 219ebff141..3f5598f647 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -88,6 +88,7 @@
var/list/ammo_states = list() //values
/obj/item/ammo_magazine/New()
+ ..()
if(multiple_sprites)
initialize_magazine_icondata(src)
diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm
index b9560be615..af53188190 100644
--- a/code/modules/research/designs.dm
+++ b/code/modules/research/designs.dm
@@ -726,17 +726,13 @@ CIRCUITS BELOW
/datum/design/circuit/AssembleDesignName()
..()
if(build_path)
- var/obj/item/weapon/circuitboard/C = new build_path()
- if(C && istype(C))
- if(C.board_type == "machine")
- name = "Machine circuit design ([item_name])"
- qdel(C)
- return
- else if(C.board_type == "computer")
- name = "Computer circuit design ([item_name])"
- qdel(C)
- return
- name = "Circuit design ([item_name])"
+ var/obj/item/weapon/circuitboard/C = build_path
+ if(initial(C.board_type) == "machine")
+ name = "Machine circuit design ([item_name])"
+ else if(initial(C.board_type) == "computer")
+ name = "Computer circuit design ([item_name])"
+ else
+ name = "Circuit design ([item_name])"
/datum/design/circuit/AssembleDesignDesc()
if(!desc)
diff --git a/code/modules/tables/tables.dm b/code/modules/tables/tables.dm
index 1c6a9ca06d..12b9e26b48 100644
--- a/code/modules/tables/tables.dm
+++ b/code/modules/tables/tables.dm
@@ -51,8 +51,9 @@
visible_message("\The [src] breaks down!")
return break_to_parts() // if we break and form shards, return them to the caller to do !FUN! things with
-/obj/structure/table/New()
+/obj/structure/table/initialize()
..()
+
// One table per turf.
for(var/obj/structure/table/T in loc)
if(T != src)
@@ -61,8 +62,6 @@
break_to_parts(full_return = 1)
return
-/obj/structure/table/initialize()
- ..()
// reset color/alpha, since they're set for nice map previews
color = "#ffffff"
alpha = 255
diff --git a/code/world.dm b/code/world.dm
index 66edcd00d2..a6d27a8850 100644
--- a/code/world.dm
+++ b/code/world.dm
@@ -73,7 +73,7 @@ var/global/datum/global_init/init = new ()
// Set up roundstart seed list.
plant_controller = new()
-
+
// Set up roundstart gene masking
xenobio_controller = new()
diff --git a/polaris.dme b/polaris.dme
index 7360a87a99..a83e390b23 100644
--- a/polaris.dme
+++ b/polaris.dme
@@ -131,7 +131,6 @@
#include "code\controllers\verbs.dm"
#include "code\controllers\voting.dm"
#include "code\controllers\observer_listener\atom\observer.dm"
-#include "code\controllers\observer_listener\datum\observer.dm"
#include "code\controllers\Processes\air.dm"
#include "code\controllers\Processes\alarm.dm"
#include "code\controllers\Processes\chemistry.dm"
@@ -143,6 +142,7 @@
#include "code\controllers\Processes\mob.dm"
#include "code\controllers\Processes\nanoui.dm"
#include "code\controllers\Processes\obj.dm"
+#include "code\controllers\Processes\scheduler.dm"
#include "code\controllers\Processes\Shuttle.dm"
#include "code\controllers\Processes\sun.dm"
#include "code\controllers\Processes\supply.dm"
@@ -181,6 +181,18 @@
#include "code\datums\locations\tau_ceti.dm"
#include "code\datums\locations\uueoa_esa.dm"
#include "code\datums\locations\vir.dm"
+#include "code\datums\observation\_debug.dm"
+#include "code\datums\observation\_defines.dm"
+#include "code\datums\observation\destroyed.dm"
+#include "code\datums\observation\dir_set.dm"
+#include "code\datums\observation\equipped.dm"
+#include "code\datums\observation\helpers.dm"
+#include "code\datums\observation\logged_in.dm"
+#include "code\datums\observation\moved.dm"
+#include "code\datums\observation\observation.dm"
+#include "code\datums\observation\task_triggered.dm"
+#include "code\datums\observation\unequipped.dm"
+#include "code\datums\observation\~cleanup.dm"
#include "code\datums\repositories\cameras.dm"
#include "code\datums\repositories\crew.dm"
#include "code\datums\repositories\repository.dm"