|
| 1 | +//* This file is explicitly licensed under the MIT license. *// |
| 2 | +//* Copyright (c) 2025 Citadel Station developers. *// |
| 3 | + |
| 4 | +/** |
| 5 | + * Connects transitively to cardinals. |
| 6 | + * |
| 7 | + * Does something very, very evil to status_traits. |
| 8 | + */ |
| 9 | +/datum/object_system/adjacency_group |
| 10 | + /// string key |
| 11 | + var/key |
| 12 | + /// current group |
| 13 | + var/datum/adjacency_group/group |
| 14 | + /// rebuild queued? |
| 15 | + var/rebuild_queued = FALSE |
| 16 | + /// connected directions |
| 17 | + var/connected_directions = NONE |
| 18 | + |
| 19 | +/datum/object_system/adjacency_group/New(obj/parent, key) |
| 20 | + src.key = key |
| 21 | + ASSERT(key) |
| 22 | + LAZYSET(parent.status_traits, TRAIT_OBJ_ADJACENCY_GROUP(src.key), src) |
| 23 | + queue_rebuild() |
| 24 | + return ..() |
| 25 | + |
| 26 | +/datum/object_system/adjacency_group/Destroy() |
| 27 | + LAZYREMOVE(parent.status_traits, TRAIT_OBJ_ADJACENCY_GROUP(key)) |
| 28 | + QDEL_NULL(group) |
| 29 | + rebuild_queued = FALSE |
| 30 | + return ..() |
| 31 | + |
| 32 | +/datum/object_system/adjacency_group/proc/parent_moved() |
| 33 | + QDEL_NULL(group) |
| 34 | + queue_rebuild() |
| 35 | + |
| 36 | +/datum/object_system/adjacency_group/proc/create_initial_data() |
| 37 | + if(rebuild_queued) |
| 38 | + return |
| 39 | + return parent.object_adjacency_group_create_initial_data(src) |
| 40 | + |
| 41 | +/datum/object_system/adjacency_group/proc/queue_rebuild() |
| 42 | + addtimer(CALLBACK(src, PROC_REF(rebuild_if_needed)), 0) |
| 43 | + rebuild_queued = TRUE |
| 44 | + |
| 45 | +/datum/object_system/adjacency_group/proc/rebuild_if_needed() |
| 46 | + if(!rebuild_queued) |
| 47 | + return |
| 48 | + rebuild_queued = FALSE |
| 49 | + if(group) |
| 50 | + return |
| 51 | + rebuild() |
| 52 | + |
| 53 | +/datum/object_system/adjacency_group/proc/rebuild() |
| 54 | + QDEL_NULL(group) |
| 55 | + var/datum/adjacency_group/new_group = new(key, create_initial_data()) |
| 56 | + new_group.build(src) |
| 57 | + |
| 58 | +/datum/adjacency_group |
| 59 | + /// all systems in group |
| 60 | + var/list/datum/object_system/adjacency_group/in_group |
| 61 | + /// string key |
| 62 | + var/key |
| 63 | + /// arbitrary data variable you can set to whatever you want |
| 64 | + var/data |
| 65 | + |
| 66 | +/datum/adjacency_group/New(key) |
| 67 | + src.key = key |
| 68 | + src.data = data |
| 69 | + in_group = list() |
| 70 | + |
| 71 | +/datum/adjacency_group/Destroy() |
| 72 | + teardown() |
| 73 | + return ..() |
| 74 | + |
| 75 | +/datum/adjacency_group/proc/build(datum/object_system/adjacency_group/from_node) |
| 76 | + // very destructive build process; when encountering 'enemy', immediately destroy it and trample over |
| 77 | + var/list/datum/object_system/adjacency_group/expanding = list(from_node) |
| 78 | + var/trait = TRAIT_OBJ_ADJACENCY_GROUP(key) |
| 79 | + while(length(expanding)) |
| 80 | + var/datum/object_system/adjacency_group/expand_this = expanding[length(expanding)] |
| 81 | + --expanding.len |
| 82 | + var/dirs_connecting = NONE |
| 83 | + |
| 84 | + var/atom/expand_loc = expand_this.parent.loc |
| 85 | + if(isturf(expand_loc)) |
| 86 | + for(var/dir in GLOB.cardinal) |
| 87 | + for(var/obj/in_cardinal_tile in get_step(expand_loc, dir)) |
| 88 | + var/datum/object_system/adjacency_group/their_cardinal_group = in_cardinal_tile.status_traits?[trait] |
| 89 | + if(their_cardinal_group) |
| 90 | + dirs_connecting |= dir |
| 91 | + if(their_cardinal_group.group == src) |
| 92 | + break |
| 93 | + expanding += in_cardinal_tile.status_traits[trait] |
| 94 | + break |
| 95 | + |
| 96 | + for(var/obj/in_tile in expand_loc) |
| 97 | + var/datum/object_system/adjacency_group/their_group = in_tile.status_traits?[trait] |
| 98 | + if(!their_group || their_group == expand_this) |
| 99 | + continue |
| 100 | + dirs_connecting |= ONTOP_BIT |
| 101 | + if(their_group.group != src) |
| 102 | + if(their_group.group) |
| 103 | + qdel(their_group.group) |
| 104 | + their_group.group = src |
| 105 | + their_group.connected_directions = dirs_connecting |
| 106 | + in_group += their_group |
| 107 | + |
| 108 | + if(expand_this.group != src) |
| 109 | + if(expand_this.group) |
| 110 | + qdel(expand_this.group) |
| 111 | + expand_this.group = src |
| 112 | + expand_this.connected_directions = dirs_connecting |
| 113 | + in_group += expand_this |
| 114 | + |
| 115 | + for(var/datum/object_system/adjacency_group/member as anything in in_group) |
| 116 | + member.parent.object_adjacency_group_join(member, src, member.connected_directions) |
| 117 | + |
| 118 | +/datum/adjacency_group/proc/teardown() |
| 119 | + for(var/datum/object_system/adjacency_group/member as anything in in_group) |
| 120 | + member.parent.object_adjacency_group_leave(member, src, member.connected_directions) |
| 121 | + member.group = null |
| 122 | + member.connected_directions = NONE |
| 123 | + member.queue_rebuild() |
| 124 | + in_group = null |
| 125 | + |
| 126 | +//* /obj hooks *// |
| 127 | + |
| 128 | +/** |
| 129 | + * Called when an adjacency group is being built from ourselves and initial data is needed |
| 130 | + */ |
| 131 | +/obj/proc/object_adjacency_group_create_initial_data(datum/object_system/adjacency_group/group_holder) |
| 132 | + return null |
| 133 | + |
| 134 | +/** |
| 135 | + * Called on adjacency group join |
| 136 | + * |
| 137 | + * @params |
| 138 | + * * group_holder - object system handling the group |
| 139 | + * * group - the group in question |
| 140 | + * * 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. |
| 141 | + */ |
| 142 | +/obj/proc/object_adjacency_group_join(datum/object_system/adjacency_group/group_holder, datum/object_system/adjacency_group/group, directions) |
| 143 | + return |
| 144 | + |
| 145 | +/** |
| 146 | + * Called on adjacency group leave |
| 147 | + * |
| 148 | + * @params |
| 149 | + * * group_holder - object system handling the group |
| 150 | + * * group - the group in question |
| 151 | + * * 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. |
| 152 | + */ |
| 153 | +/obj/proc/object_adjacency_group_leave(datum/object_system/adjacency_group/group_holder, datum/object_system/adjacency_group/group, directions) |
| 154 | + return |
0 commit comments