Repository: evennia/evennia

Issue:
[BUG - Develop] inline funcparsers sent to `msg_contents` parses the same for everyone
#### Describe the bug
When passing an inline func for the new funcparser, it parses the string from the perspective of the first object in the list of contents and then uses that same parsed message to all of the successive messages.

#### To Reproduce
Steps to reproduce the behavior:
1. Add the test command class I provided under "Additional context"
2. Create two characters and have them each execute the command.
3. The string will print with the correct *actor* but from the perspective of whichever character was created or entered the room first, to both characters.

#### Expected behavior
I believe it's supposed to parse each time so the viewer sees the correct names relative to themself.

#### Develop-branch commit
3992f37da

#### Additional context
```python
class TestFuncparser(Command):
    """Usage: test <object>"""
    key = "test"

    def func(self):
        caller = self.caller
        location = caller.location

        target = caller.search(self.args.strip())
        if not target:
            return

        message = f"$You() point at $you({target.name})."

        location.msg_contents(message, from_obj=caller, mapping={"you": caller, target.name: target})
```


Discussion:
A quick additional "demo" of it, in case my explanation wasn't clear.

Here, I'm on my admin account, which I have two characters for, "admin" and "zeno". In a separate session I have a test account, with a character named Monty.

Here's what it looks like for account admin:
```
py here.contents
>>> here.contents
[admin, Monty]
test monty
You point at Monty(#3).
ic zeno

You become zeno.
Limbo(#2)
[...]

Characters: Monty(#3)
py here.contents
>>> here.contents
[Monty, zeno]
test monty
zeno points at you.
```

Meanwhile, this is what Monty saw:
```
You point at Monty(#3).
admin has left the game.
zeno has entered the game.
zeno points at you.
```

You can see that both times, the message *both* characters received was from the perspective of the character who was first in the `contents` list.
Hm, this has been tested quite a bit. There is no need for `you: caller` in the mapping, this is taken from `from_obj`. I wonder if this is what confuses the system? 
> Hm, this has been tested quite a bit. There is no need for `you: caller` in the mapping, this is taken from `from_obj`. I wonder if this is what confuses the system?

I just tried again to verify, since it's been a while, and it's the same without it. I added it in originally to eliminate possible missing information, but it made no difference.
I took a quick look at the `msg_contents` function and found the problem:
https://github.com/evennia/evennia/blob/5ae3941841827c1b37ca03890ba79fc8774fee0c/evennia/objects/objects.py#L766-L767

It's replacing `inmessage` with the parsed version on the first receiver, causing all later receivers to get that parsed version instead of reparsing. I have some time at the moment so I'll put in a quick PR to fix it.
> 

I can also confirm that its the case of who is lead in  db_Characters: 

Characters: Ant1(#7), Sk33t3rson(#1)

from Skeet3rson perspective
You open a Metal reinforced gate
from Ant1 perspective
You open a Metal reinforced gate

Characters:  Sk33t3rson(#1), Ant1(#7)

from Skeet3rson perspective
Ant1(#7) opens a Metal reinforced gate
from Ant1 perspective
Ant1(#7) opens a Metal reinforced gate


Resolving patch:
diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py
--- a/evennia/objects/objects.py
+++ b/evennia/objects/objects.py
@@ -763,7 +763,7 @@ def msg_contents(
         for receiver in contents:
 
             # actor-stance replacements
-            inmessage = _MSG_CONTENTS_PARSER.parse(
+            outmessage = _MSG_CONTENTS_PARSER.parse(
                 inmessage,
                 raise_errors=raise_funcparse_errors,
                 return_string=True,
@@ -773,7 +773,7 @@ def msg_contents(
             )
 
             # director-stance replacements
-            outmessage = inmessage.format_map(
+            outmessage = outmessage.format_map(
                 {
                     key: obj.get_display_name(looker=receiver)
                     if hasattr(obj, "get_display_name")


Test patch: