ID:1936996
 
BYOND Version:508
Operating System:Windows 7 Pro 64-bit
Web Browser:Chrome 45.0.2454.85
Applies to:DM Language
Status: Deferred

This issue may be low priority or very difficult to fix, and has been put on the back burner for the time being.
Descriptive Problem Summary: The locate() proc returns true when it should be false when you use #define macros as seen below.

Numbered Steps to Reproduce Problem:
1. Create a #define macro that returns some text that would be used for a tag string.
2. Use the #define macro to search for an existing datum. You'll get a true value when it should be false.

Code Snippet (if applicable) to Reproduce Problem:
#define UNIQUE_ID(a) (a.unique_id || a.unique_id())

atom
var tmp/unique_id

proc/unique_id()
unique_id = "\ref[src]"
return unique_id

mob
var/tmp/somedatum/sd

verb/trythis()
var somedatum/existing = locate("[UNIQUE_ID(src)]_and_[UNIQUE_ID(src)]")
if(!existing)
sd = new/somedatum(src,src)
else
world.log << "sd already exists!"

somedatum
New(atom/a, atom/b)
tag = "[UNIQUE_ID(a)]_and_[UNIQUE_ID(b)]"


Expected Results: To get the correct return value regardless of whether I'm using a #define macro or hard-text. Currently I'm forced to set the tag of non-client based mobs to their \ref value upon creation, and use the tag variable from there. There's nothing wrong with this (I save a variable with this method, so that's a plus that came from this), but I expect #define macros to act no differently.

Actual Results: locate() returns the wrong value, and in the case of my project, the game hard-crashes due (the window disappears without warning) to executing the wrong statements and running into runtime errors due to a non-existent mob.

Does the problem occur:
Every time? Or how often? Every time.
In other games? All; I reproduced it in a test project.
In other user accounts? N/A
On other computers? N/A

When does the problem NOT occur? When I avoid using #define inside of the locate() proc.

Did the problem NOT occur in any earlier versions? If so, what was the last version that worked? (Visit http://www.byond.com/download/build to download old versions for testing.)
Though I'm using the latest 508.1299, I tested as far back as 508.1292 and it still occurred.

Workarounds: Don't use #define inside of locate().
I don't think #define is your problem at all. I think the problem is that your tag still contains the [0x...] ref, and locate() is merely interpreting the first ref it sees in that tag. If you strip the brackets out of unique_id, I suspect the issue will go away.
In response to Lummox JR
Ok, that is the issue.

So now my question is: why does locate() act like that? I would expect it to evaluate the whole string instead of dropping off as soon as it finds a viable search argument.

I could remove the brackets, but that just sounds ugly. I think it makes more sense in this case for locate() not to drop off.
It's a matter of simplicity. It probably could be "fixed", but I question the usefulness of doing so.
In response to Lummox JR
In my particular case, I was using the unique_ids of two atoms involved in combat to locate() the combat session they are tied to.

So once they enter combat, a /combat_session datum is created which manages the atoms involved. Its tag is changed to:

tag = "[attacker]_vs_[defender]"


...where defender and attacker are unique_ids (or a tag or \ref macro).

So the system would work fine as long as a client initiated combat, otherwise whatever tag or ref locate() drops off on crashes the attached atom.

I could go either way probably and I'd likely make my own unique_id generation to avoid having to cut brackets for non-client mobs.

However, locate()'s behavior truly makes no sense to me. If I pass a string to a proc, I expect the proc to take the whole string into consideration, not part of it. I understand its for simplicity and it's probably faster, but what other proc acts like that?

But eh, ball's in your court now. I'll proceed based on your verdict. Appreciate it.
Looks like this opens a can of worms. locate() also has a special form where it looks for brackets, and if it finds any, it does a tag lookup on the substring between the first open bracket and the first close bracket.

Because there's probably no way to fix this without breaking some legacy code (though admittedly, I doubt much), I'm going to count this as Deferred.
Lummox JR changed status to 'Deferred'