Region

by Forum_account
Lets you specify regions of the map that trigger Entered and Exited events.
ID:112187
 
Keywords: library, region
A priest, a rabbi, and a DM developer walk into a bar and... nothing happens because the bar is defined inside of a BYOND game and the developer had no way to define an Entered proc to execute when mobs step into the bar.

If you were expecting a funny punchline you should have known better.

The problem is that the bar is represented by many turfs so defining the Entered proc to detect when a mob enters the bar wouldn't work, it'd catch every step taken while inside the bar. A single area could be used, but in the case of this joke, the developer was already using areas for something else.

This is a problem I've run into. Areas can be extremely useful but two useful features may both rely on the use of areas and are therefore incompatible.

The solution I've come up with is to define a type of object that is a child of /obj, so it can be placed on the map in the map editor and you can have multiple of these objects per turf. In the library I call this object /region. Every turf has a list of regions that it's a part of. The region's constructor adds itself to it's loc's region list. When you enter a turf, the library checks for regions that you're entering and exiting.

Only a single instance of the region object is kept. They're all stored in a global list and their loc is set to null, the way you don't have to worry about the region objects coming up in things like "for(var/obj/o in view())". Also, because only one instance is kept you don't have to worry about having tons of objects stored in memory. In terms of memory this isn't really any different from using areas. The only catch, and I haven't really played around with it, is that each region object has a constructor so if you have tons of region objects, you might notice some delays when your game is loading.

Hub entry: Forum_account.Region
Yeah I've found these sort of objects to be very useful myself. Especially since areas are so damned fast in dynamic lighting situations. Dynamic Lighting + Another feature that needs /area esque functionality becomes a bit of a hassle, though traditionally I've used datums as /area substitutes and not /obj.

Are you overriding turf.Enter() and turf.Exit() for convenient content list managing for your Region objects? Like if I wanted all movable atoms within a Region, I don't want to loop through all of the turfs' contents.

[EDIT]: Read through the hub, looks like you do have that. Hot stuff.
I always thought, for those instances where an area serves well for a purpose, one could simply tack on multiple datums that would be handed the /area's proc calls.

So, when a mob enters the bar, instead of the /area handling what happens, the area hands the call down by looping through pertinent datums.

I've never put this together, but that's how I had intended to do so had the situation ever cropped up.
This is exactly the sort of thing which would benefit greatly from an atom filter/selector in the map editor.
Vermolius wrote:
So, when a mob enters the bar, instead of the /area handling what happens, the area hands the call down by looping through pertinent datums.

The problem is, how do you know which datums are pertinent? This method let's you use the map editor to place the regions.

D4RK3 54B3R wrote:
Like if I wanted all movable atoms within a Region, I don't want to loop through all of the turfs' contents.

Currently I don't maintain this info. The region doesn't even have a list of turfs in it.

Keeping track of mobs would be tough because you can enter and exit by changing loc directly. In these cases its expected that Entered and Exited don't get called, but I'd need some way to know that the mob is in the region. The list of turfs in a region is possible because they won't change.
It'd be sort of like adding event listeners.
Vermolius wrote:
It'd be sort of like adding event listeners.

I understand that, but how do you define the sub-area? By creating a hard-coded list of turfs at runtime?

I'm not sure how much of a hassle it will be to use this library for a real project with big maps, but I made it this way so you can use the map editor to manage regions. My plan is to use this for camera control in my Sidescroller library. Each region would represent a set of camera rules (ex: only scroll horizontally, don't scroll past this point, etc.). You just need to know what region the player is in to enforce these rules, and it won't interfere with other uses of areas.
It turns out that using traditional operators on lists is much faster than using the "in" operator.

So you can do something like this without much of a slowdown


turf/Entered(atom/movable/A)
Region.contents.Add(list(A)-Region.contents)
.=..()
I'll be fixing up the code because it was thrown together quickly, but not for performance reasons. If this library ever ends up being the bottleneck, your program must not be doing very much :-)

turf/Entered(atom/movable/A)
Region.contents.Add(list(A)-Region.contents)
.=..()

I'm not sure if I can use contents like that, the mob should still be in the turf's contents. Also, that'll only track mobs that enter and exit by certain means, setting a mob's loc to put them inside the region won't trigger the entered event so they wouldn't get added to the list.