Files
2025-07-06 20:49:06 +02:00

155 lines
4.9 KiB
Plaintext

//* This file is explicitly licensed under the MIT license. *//
//* Copyright (c) 2025 Citadel Station developers. *//
/**
* Connects transitively to cardinals.
*
* Does something very, very evil to status_traits.
*/
/datum/object_system/adjacency_group
/// string key
var/key
/// current group
var/datum/adjacency_group/group
/// rebuild queued?
var/rebuild_queued = FALSE
/// connected directions
var/connected_directions = NONE
/datum/object_system/adjacency_group/New(obj/parent, key)
src.key = key
ASSERT(key)
LAZYSET(parent.status_traits, TRAIT_OBJ_ADJACENCY_GROUP(src.key), src)
queue_rebuild()
return ..()
/datum/object_system/adjacency_group/Destroy()
LAZYREMOVE(parent.status_traits, TRAIT_OBJ_ADJACENCY_GROUP(key))
QDEL_NULL(group)
rebuild_queued = FALSE
return ..()
/datum/object_system/adjacency_group/proc/parent_moved()
QDEL_NULL(group)
queue_rebuild()
/datum/object_system/adjacency_group/proc/create_initial_data()
if(rebuild_queued)
return
return parent.object_adjacency_group_create_initial_data(src)
/datum/object_system/adjacency_group/proc/queue_rebuild()
addtimer(CALLBACK(src, PROC_REF(rebuild_if_needed)), 0)
rebuild_queued = TRUE
/datum/object_system/adjacency_group/proc/rebuild_if_needed()
if(!rebuild_queued)
return
rebuild_queued = FALSE
if(group)
return
rebuild()
/datum/object_system/adjacency_group/proc/rebuild()
QDEL_NULL(group)
var/datum/adjacency_group/new_group = new(key, create_initial_data())
new_group.build(src)
/datum/adjacency_group
/// all systems in group
var/list/datum/object_system/adjacency_group/in_group
/// string key
var/key
/// arbitrary data variable you can set to whatever you want
var/data
/datum/adjacency_group/New(key)
src.key = key
src.data = data
in_group = list()
/datum/adjacency_group/Destroy()
teardown()
return ..()
/datum/adjacency_group/proc/build(datum/object_system/adjacency_group/from_node)
// very destructive build process; when encountering 'enemy', immediately destroy it and trample over
var/list/datum/object_system/adjacency_group/expanding = list(from_node)
var/trait = TRAIT_OBJ_ADJACENCY_GROUP(key)
while(length(expanding))
var/datum/object_system/adjacency_group/expand_this = expanding[length(expanding)]
--expanding.len
var/dirs_connecting = NONE
var/atom/expand_loc = expand_this.parent.loc
if(isturf(expand_loc))
for(var/dir in GLOB.cardinal)
for(var/obj/in_cardinal_tile in get_step(expand_loc, dir))
var/datum/object_system/adjacency_group/their_cardinal_group = in_cardinal_tile.status_traits?[trait]
if(their_cardinal_group)
dirs_connecting |= dir
if(their_cardinal_group.group == src)
break
expanding += in_cardinal_tile.status_traits[trait]
break
for(var/obj/in_tile in expand_loc)
var/datum/object_system/adjacency_group/their_group = in_tile.status_traits?[trait]
if(!their_group || their_group == expand_this)
continue
dirs_connecting |= ONTOP_BIT
if(their_group.group != src)
if(their_group.group)
qdel(their_group.group)
their_group.group = src
their_group.connected_directions = dirs_connecting
in_group += their_group
if(expand_this.group != src)
if(expand_this.group)
qdel(expand_this.group)
expand_this.group = src
expand_this.connected_directions = dirs_connecting
in_group += expand_this
for(var/datum/object_system/adjacency_group/member as anything in in_group)
member.parent.object_adjacency_group_join(member, src, member.connected_directions)
/datum/adjacency_group/proc/teardown()
for(var/datum/object_system/adjacency_group/member as anything in in_group)
member.parent.object_adjacency_group_leave(member, src, member.connected_directions)
member.group = null
member.connected_directions = NONE
member.queue_rebuild()
in_group = null
//* /obj hooks *//
/**
* Called when an adjacency group is being built from ourselves and initial data is needed
*/
/obj/proc/object_adjacency_group_create_initial_data(datum/object_system/adjacency_group/group_holder)
return null
/**
* Called on adjacency group join
*
* @params
* * group_holder - object system handling the group
* * group - the group in question
* * directions - directions we're connecting in, as X_BIT (e.g. NORTHEAST_BIT). This will only have cardinals and ONTOP_BIT if something is atop us.
*/
/obj/proc/object_adjacency_group_join(datum/object_system/adjacency_group/group_holder, datum/object_system/adjacency_group/group, directions)
return
/**
* Called on adjacency group leave
*
* @params
* * group_holder - object system handling the group
* * group - the group in question
* * directions - directions we **were** connected in, as X_BIT (e.g. NORTHEAST_BIT). This will only have cardinals and ONTOP_BIT if something was atop us.
*/
/obj/proc/object_adjacency_group_leave(datum/object_system/adjacency_group/group_holder, datum/object_system/adjacency_group/group, directions)
return