ID:2572416
 
Code:
mob/verb/Rest()

var/image/Rest = new('Resting Overlay.dmi')
Rest.appearance_flags = RESET_COLOR

if(src.resting)
src.overlays -= Rest
src.busy = 0
src.resting = 0
src << ">> You stop resting."
return

if(src.busy)
return

src.overlays += Rest
src.busy = 1
src << ">> You begin to rest."
src.resting = 1

while(src.resting)
sleep(20)

if(src.resting)
src.stamina += 2

if(src.stamina >= 100)
src.stamina = 100

for(var/turf/Tiles/T027 in oview(0,src))
src.hp_min += 2
if(src.hp_min >= src.hp_max)
src.hp_min = src.hp_max

src.mp_min += 2
if(src.mp_min >= src.mp_max)
src.mp_min = src.mp_max


Problem description:
Intent: When a player rests anywhere besides on turf T027 (bed), all they recover is stamina. While on T027, they also recover hp and mp. The current above example acts as if you are always on T027, regardless of where you are.

I also tried if(src in /turf/Tiles/T027) instead of for(var/turf/Tiles/T027 in oview(0,src)), which compiles fine but does not recover hp or mp.

I am wondering if perhaps I should be using a defined area instead on the map, but thought if I can just check for the specific turf, what's the point of making a special area?
if(istype(src.loc,/turf/Tiles/T027))


Is probably the easiest way to do it (loc is the turf you're standing on if you're on a turf).

HOWEVER, having something like a bed be a turf and not an obj is probably a bad design choice that's gonna bite you in the butt down the road.
Also, at a quick glance, you should probably not be recreating the "Rest" image every time you use this verb, you can make a a mob variable and set it once and reuse it as needed.

Calling new/image in this way is going to absolutely murder performance, especially if someone decides they want to spam the rest verb.
Where you went wrong:
for(var/turf/Tiles/T027 in oview(0,src))

T027 is the name of the variable. It's not included in the type of the variable, so the loop only filters to Tiles.

Also, repeating the action every iteration may be a problem when you're on multiple turfs. That isn't a problem if you use Nadrew's solution, but if straddling turfs is possible, you should use "locs" instead:
if(locate(/turf/Tiles/T027) in locs)

Also, be careful about adding behaviors to turfs. If you ever stack turfs in the map editor, only the topmost turf actually exists at that position, so behaviors specific to the lower turfs won't happen there. That's where Nadrew's suggestion of using an obj instead comes from. If you do use an object instead, you could use "bounds()" to check for it:
if(locate(/obj/bed) in bounds())
(Technically, you could use bounds() instead of locs for that example, so it would work whether you're detecting a turf or an obj, but it's more efficient to be as specific as possible to reduce the size of the list being searched.)

About the /image creation spam, you can use the "global" var modifier to easily make the image shared between all calls to Rest():
mob/verb/Rest()
var/global/image/Rest
if(!Rest)
Rest = new('Resting Overlay.dmi')
Rest.appearance_flags = RESET_COLOR
// etc.
Thanks again, Nadrew.

Part of the reason why the image was done the way it is, is due to the fact I recycle player sprites and use color to change the color of the player sprite, since they are very simple, being white '@' and then using color to change that color to represent different things.

I noticed when I used overlays as a mob variable, it effected the overlays as well. I did some searching on the forums and discovered RESET_COLOR.

I'll be honest, I couldn't figure out a way to use RESET_COLOR with the mob's variable. Is there a way to do something like setting it as a var and then using RESET_COLOR on it?

Edit: I just considered the possibility of having the overlay vars defined like..

    var/image/Rest = new('Resting Overlay.dmi')
Rest.appearance_flags = RESET_COLOR
src.RestOverlay = Rest


I didn't even think about that at the time. Will that work? I could do that during character creation, unless there's an easier way.
Since it's going to be different for each player, you can make it a /mob/var instead of a global one (or a local one in the proc), yes. You don't need to assign a secondary variable though.

// Outside of any verb/proc stuff
mob/var/image/RestOverlay

// Then inside of your verb/proc/whatever
if(!RestOverlay)
RestOverlay = image('Resting Overlay.dmi')
RestOverlay.appearance_flags = RESET_COLOR

overlays += RestOverlay

// And later
overlays -= src.RestOverlay
In response to Nadrew
I'm not seeing how the image is different for each player...
I misread what he said about changing the color and the sort.

Defining global variables inside of verbs is a good way to lose track of the thing by the way, I highly recommend never doing that.
Thanks Kaiochao.

There are very few instances in which players will be stradling turfs, due to the basic art style I am using.

https://imgur.com/a/A60uyZJ

Nothing is really layering on top of each other besides a few instances of trees, which are dense anyways.

So I guess the question is, if I think it's unlikely since there's very few stacks on the map, would there be any other reason to change it to an object?

I also didn't know about bounds(), so thanks for that. Does bounds() work with areas as well?
By straddling turfs he means if you're using pixel movement mode, if you're using tile movement mode it's not possible to be on top of two turfs.

bounds() is used to check if two things are colliding, and is more useful in pixel movement mode than tile mode where you can just check for tile overlaps using locate()
Alright, thanks for the help. I am using tile movement to better emulate the look of old DOS roguelike games. Everyone has been very helpful and insightful.
Tile mode is a lot simpler than pixel mode in a lot of places, including detecting if something is on something. A simple.

var/obj/someobj/found = locate() in turf
if(found)
// Do stuff


Is usually enough to do the trick, using locate() without an argument in that way will imply the type, in this case it would be "/obj/someobj" and assigning the return value to the "found" variable. locate() will return a reference to the first thing of the type in the container, or null if there isn't one.

If you need to grab multiple things of the same type, you'd need a for() but over the same turf container.
Hower, pixel-mode procs like Cross() and Crossed() have plenty of value in tile-mode if you want to detect/prevent collision without using Bump() or Enter()/Entered().
Tile movement mode supports multi-tiled bounds. You can have 2-tile by 3-tile bounds and still have tile gliding.

I've always felt that it's wrong to say that Cross/Crossed/locs/bounds() are "pixel movement" features just because they came out in the same version. They all apply to tile movement mode in the same way.

Also, bounds() never includes areas, but you can get them using locs:
atom/movable/proc/AreasInBounds()
if(!z) // Not on the map.
return list()
var/list/areas_in_bounds = new
for(var/turf/loc as anything in locs)
areas_in_bounds[loc.loc] = TRUE // Prevents duplicate entries.
return areas_in_bounds

Also, as far as we can tell for the moment, the overlay image isn't used outside of the proc at all. In general, if a var can be local to a smaller scope, it should be. It's easy enough to move it out when it becomes necessary.