ID:1993367
 
(See the best response by PJB3005.)
Code:
obj
building
var/multi_build = 0 // value > 0 if the central obj of the building
var/obj/building/list/building_controller[]
core
multi_build = 1 // how large the building might be



world/New()
..()
spawn(10) // post-world creation building assignment
for (var/obj/building/A in world)
if (A.multi_build > 0)
var/obj/building/list/new_building[] = new()
var/obj/building/list/buildings_in_range = range(A, A.multi_build)
for (var/obj/building/B in buildings_in_range)
new_building += B
for (var/obj/building/B in buildings_in_range)
B.building_controller = new_building


Problem description:

I'm trying to build multi-object buildings. I place down a /obj/building/core and surround it with /obj/building to make a 3x3 building. I can currently create a var/obj/building/list/building_controller[] no problem, and assign that list as a reference to all the /obj/building parts of the building.

However, I want to make a database of building_controllers, so I can access information from one (assumedly global?) location. I'm essentially trying to make a list of a list, which could vary in size.

I've tried using 2d lists but always struggle with merging 1d lists into it (building_controller). I think what I need is a "jagged list" but I don't know how to create/use one in BYOND, or whether there's a better alternative.

Rather than just truck on and find something that _does_ work, I'm more interested in finding the best way to work this.

Thankyou for your time!

Best response
Okay so, this is what I've gathered from this thread:

  • Every building object needs to have a list of buildings, which is all the buildings it's connected to, including itself.
  • You want a global list of these lists.


Now, personally I'd make these "building controllers" actual datums, but whatever.

/var/global/list/building_controllers   = list() // List containing lists of buildings.
/var/global/list/obj/building/buildings = list() // List of all buildings; and optimization. Looping through world is slow.

/obj/building
var/multi_build = 0 // Value > 0 if the central obj of the building.
var/list/obj/building/building_controller // List of all buildings attached to this one (including itself).

/obj/building/core
multi_build = 1

/obj/building/New()
. = ..()
global.buildings += src

/obj/building/Destroy()
. = ..()
global.buildings -= src

/world/New()
. = ..()
spawn(10) // Post-world creation building assignment.
setup_building_controllers()

/world/proc/setup_building_controllers()
for(var/obj/building/B in global.buildings)
if(B.multi_build <= 0)
continue

var/list/obj/building/new_controller = list()
var/list/obj/building/buildings_in_range = range(A, A.multi_build)
for(var/obj/building/N in buildings_in_range)
new_controller += N
N.building_controller = new_controller // Lists are objects, so these will all be persistent.

global.building_controllers[++len] = new_controller // This inserts the list into the list.
Thankyou very much PJB,

The last line is probably the main problem I have with this. I was surprised to be able to pull individual /obj/building out by using the following:

world << global.building_controllers[1][1]


I didn't turn this into a datum for the sake of simplicity. I'm actually going to be doing that now but I shouldn't have a problem with it thanks to your answer.

I also noted your comment about lists being objects, so get referenced instead of directly modified. I'll try to bear that in mind for future.

At the bottom you'll find my edits which make it work (changing references pointing at A to point at B, and changing Destroy() to Del() as I have no destroy proc)

/var/global/list/building_controllers   = list() // List containing lists of buildings.
/var/global/list/obj/building/buildings = list() // List of all buildings; and optimization. Looping through world is slow.

/obj/building
var/multi_build = 0 // Value > 0 if the central obj of the building.
var/list/obj/building/building_controller // List of all buildings attached to this one (including itself).

/obj/building/core
multi_build = 1

/obj/building/New()
. = ..()
global.buildings += src

/obj/building/Del()
. = ..()
global.buildings -= src

/world/New()
. = ..()
spawn(10) // Post-world creation building assignment.
setup_building_controllers()

/world/proc/setup_building_controllers()
for(var/obj/building/B in global.buildings)
if(B.multi_build <= 0)
continue

var/list/obj/building/new_controller = list()
var/list/obj/building/buildings_in_range = range(B, B.multi_build)
for(var/obj/building/N in buildings_in_range)
new_controller += N
N.building_controller = new_controller // Lists are objects, so these will all be persistent.

global.building_controllers[++global.building_controllers.len] = new_controller // This inserts the list into the list.


I do find myself left with one question though.

What's the difference between ..() and . = ..()
Ah whoops I typed Destroy() because that's basically the Del() equivalent in SS13, I did mean Del().

Also, the different between . = ..() and ..(), is that the return value of ..() gets called down, I'm unsure if it matters for world/New(), but it can certainly matter for others (. is the default return value, which is used if you do not do return x)
In Del() you should call ..() at the end of the proc, not the beginning.
In response to Lummox JR
Lummox JR wrote:
In Del() you should call ..() at the end of the proc, not the beginning.

Good catch, thanks.