Impersonation Errors with MoveTokenToMap()

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice

Post Reply
User avatar
Altrunchen
Giant
Posts: 135
Joined: Sun Dec 02, 2012 3:01 pm

Impersonation Errors with MoveTokenToMap()

Post by Altrunchen »

Hello so what I'm trying to do at present is make a macro that works like this:

1.) Player is currently impersonating their own token.
2.) Player selects and clicks on an immmobile token with the macro I'm making on it.
3.) The macro sends the impersonated token to the selected map.

But what is happening is:

1.) Player is currently impersonating their own token.
2.) Player selects and clicks on immobile token with the macro I'm making on it.
3.) The macro sends the selected token (not the impersonated player token) to the map instead.

Here is the code I'm using, I honestly have no clue what is going on here or what I'm doing wrong. Apparently though, the macro recognizes the selected token as an impersonated token as well (I ran tests to see what the impersonated token and the selected token names were, the same ID pops up twice).

Code: Select all

<!-- Get current map name-->
[h: ThisMap = getCurrentMapName()]

<!--Get list of all maps-->
[h: MapList = getAllMapNames()]

<!--Get rid of the current map name from the list of maps-->
[h: ThisMapIndex = listFind(MapList, ThisMap)]
[h: MapList = listDelete(MapList, ThisMapIndex)]

<!--Sort the list of maps-->
[h: MapList = listSort(MapList, 'A')]

<!-- Prompt User for target map -->
[h:status = input(
"TargetMap|"+MapList+"|Which Map is this character going to?|LIST|SELECT = 0 VALUE = STRING")]
[h:abort(status)]

<!--Get destination on target map-->
[h: Xcoord = 1]
[h: Ycoord = 1]
[h: Zcoord = 1]

<!--Get the impersonated token-->
[h: ImpToken = getImpersonatedName()]

<!--Move Token to destination-->
[h: moveTokenToMap(ImpToken, TargetMap, Xcoord, Ycoord, Zcoord)]
I know that there are macro kits that are already made, but I have a specific use for this in mind and I'd rather just make it and learn for myself. Unfortunately though, I have no idea what is wrong with this code. Can anyone help me please?
Image

User avatar
Irrlicht
Dragon
Posts: 426
Joined: Mon Feb 09, 2009 10:53 am

Re: Impersonation Errors with MoveTokenToMap()

Post by Irrlicht »

I've tried to test it. Apparently, if you put a macro with getImpersonated() or getImpersonatedName on a specific token, those functions only return that token as the impersonated one, even if it really isn't. More precisely, it seems that they do so because for those functions the selection overrides the impersonation (and you have to keep a token selected to use a macro that only such token has). Unfortunately, deselectTokens() doesn't seem to help, it still gets overridden.
Instead, if you put the macro on a neutral panel (Campaign or Global), you get the correct result because no selection is getting in the way.
So, your macro would work perfectly, if clicked from the Campaign/Global panel, but alas you can't use the trick of putting it there while giving the specific token an "utility" macro linking to the real one in the neutral panel.

At this point, unless one of the many good people here has a solution, the only workarounds I can suggest you are:
1) You put that macro on Global or Campaign (in this case, make sure players can access the panel), and instead of clicking on a token and its travel-macro, they click in the general panel. I get the feeling that you wanted to have many such macros, each with different positions, but that would need to be discussed further, if it's the case.
2) This one requires some rewriting. Drop the functions based on impersonation, and instead give each player token a "travel macro" that will check if there are "destination tokens" within a given range and will let the player select which one to use (in this way, a player will need to be within reach of a door to use it and go to the related building's map, for example). Once that is selected, the macro will retrieve the destination info (stored in a macro in the destination token), process them and send the player to that place. Destination info should be the X, Y, Z coordinates for sure, but maybe also a specific sublist of maps, rather than all of them.
For now I don't have time to back this up with actual code, but maybe you can do it alone, provided you wish to take this route.

EDIT
Pardon me, while trying to do #2 above, I remembered that you can't call a macro residing on just any token you want, especially from another token's macro. At best you could call a macro of the currently impersonated token from a trusted macro (and this is an issue also for some other courses of action I could think up).
So, the workaround can get tricky, but I'd like to see if someone else has better ideas.
"There are many ways my Son, to find where the souls of Demons remain...
But it takes only one second of despair and of doubt until, at last, your Soul they will gain..."

User avatar
Altrunchen
Giant
Posts: 135
Joined: Sun Dec 02, 2012 3:01 pm

Re: Impersonation Errors with MoveTokenToMap()

Post by Altrunchen »

Irrlicht wrote:I've tried to test it. Apparently, if you put a macro with getImpersonated() or getImpersonatedName on a specific token, those functions only return that token as the impersonated one, even if it really isn't. More precisely, it seems that they do so because for those functions the selection overrides the impersonation (and you have to keep a token selected to use a macro that only such token has). Unfortunately, deselectTokens() doesn't seem to help, it still gets overridden.
Instead, if you put the macro on a neutral panel (Campaign or Global), you get the correct result because no selection is getting in the way.
So, your macro would work perfectly, if clicked from the Campaign/Global panel, but alas you can't use the trick of putting it there while giving the specific token an "utility" macro linking to the real one in the neutral panel.

At this point, unless one of the many good people here has a solution, the only workarounds I can suggest you are:
1) You put that macro on Global or Campaign (in this case, make sure players can access the panel), and instead of clicking on a token and its travel-macro, they click in the general panel. I get the feeling that you wanted to have many such macros, each with different positions, but that would need to be discussed further, if it's the case.
2) This one requires some rewriting. Drop the functions based on impersonation, and instead give each player token a "travel macro" that will check if there are "destination tokens" within a given range and will let the player select which one to use (in this way, a player will need to be within reach of a door to use it and go to the related building's map, for example). Once that is selected, the macro will retrieve the destination info (stored in a macro in the destination token), process them and send the player to that place. Destination info should be the X, Y, Z coordinates for sure, but maybe also a specific sublist of maps, rather than all of them.
For now I don't have time to back this up with actual code, but maybe you can do it alone, provided you wish to take this route.

EDIT
Pardon me, while trying to do #2 above, I remembered that you can't call a macro residing on just any token you want, especially from another token's macro. At best you could call a macro of the currently impersonated token from a trusted macro (and this is an issue also for some other courses of action I could think up).
So, the workaround can get tricky, but I'd like to see if someone else has better ideas.
I see what you're saying, and thanks for the response. But the sad truth is that I actually did want there to be many utility tokens. This way I could place them on top of staircases, doors, or whatever and essentially make them into load doors like the ones from Bethesda games. But if you're saying that there is no real workaround for that, then I'm really sad to hear that, but thanks anyhow.

Does anyone, perhaps a developer for Maptool, know if there's a solution to this dilemma?
Image

User avatar
Irrlicht
Dragon
Posts: 426
Joined: Mon Feb 09, 2009 10:53 am

Re: Impersonation Errors with MoveTokenToMap()

Post by Irrlicht »

If you're alright with having the travel macro in the Campaign or Global panel, or among each PC's own commands (Impersonated panel), maybe you can mix up the two things. A player would have to be in reach of a travel token, but rather than clicking that token he'd use the universal macro. This way the issue of trusted macros should be solved, if I'm not missing something (the macro in the Impersonated/Campaign/Global panel would call one in aLibrary token, and that one would be trusted).
"There are many ways my Son, to find where the souls of Demons remain...
But it takes only one second of despair and of doubt until, at last, your Soul they will gain..."

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: Impersonation Errors with MoveTokenToMap()

Post by wolph42 »

Im very unfamiliar with the impersonation functions as I never use them, but lets take your experience that they don't work in this instance.
There are other ways to do this, for one I suppose that if a player wishes to use such a door, that their token needs to be standing next to it, correct?
So you can you Wiki: getTokenNames() on the door and get all tokens within one square of the door. Now if this is one token, you can immediately move it to its destination.
In the other case you could either consider a dropdown list with images (I have a function in the bot that is very helpful for that) OR maybe even better, you could create an input with checkboxes per token so that one player can activate the door for multiple players next to her.

you could also consider to ask players to run a macro at start up that links their token to their username and store that on a json object on a lib:token.
E.g. on lib:token
'playerTokens': {"Tom":"Kal'Rahzad The Powerfull","Sue The Manipulator":"Eleanor","Tim":"Morkoz The Destroyer"}
then when a player uses the door, get the json object and retrieve the token name from it.

User avatar
Irrlicht
Dragon
Posts: 426
Joined: Mon Feb 09, 2009 10:53 am

Re: Impersonation Errors with MoveTokenToMap()

Post by Irrlicht »

Alright, I've tested this and it works; as said above, the only difference with th original intent is that the travel macro is among a token's own macros, rather than in the travel token itself.

1) Create a new set of token properties in the campaign properties window; call it "Travel" or whatever you want, and add these properties:

Xdestination:1
Ydestination:1
Zdestination:1
MapDestination:None

2) Create one (or more) travel tokens. Their names will need to ALWAYS start with the same word or words; here I chose to have them start with "Travel to" (their full names being "Travel to Forest", "Travel to Cellar", and such).
For these tokens set the group of properties to "Travel", the one you just created. Now, for each of these tokens, edit the coordinates and target map (manually or by making a macro for that purpose).

3) Assuming you don't already have a library token, create one (drag a token to the Hidden layer, set it to "NPC" and "Visible to Players") and name it Lib:Whatever. Create a new macro in its panel, call it "Travelling", and add to it the following code:

Code: Select all

<!-- Get names of all tokens on map -->
[h: Names = getTokenNames()]

<!-- Make a list of the actual travel tokens present -->
[h: TravelTokens = ""]
[h, foreach(Name, Names), code:
{
[IsTravel = startsWith(Name, "Travel")]
[if(IsTravel == 1): TravelTokens = listAppend(TravelTokens, Name)]
}]

<!-- Reduce the above list to the tokens within 5 feet from the player who used the macro; of course you can set a greater reach or remove it entirely -->
[h: AvailableTravels = ""]
[h, foreach(Token, TravelTokens), code:
{
[Distance = getDistance(Token)]
[if(Distance <= 5): AvailableTravels = listAppend(AvailableTravels, Token)]
}]

<!-- Prompt choice among travel tokens in reach -->
[h: status = input(
"ChosenTravel|" + AvailableTravels + "|Available Locations|LIST|VALUE=STRING"
)]

[h: abort(status)]

<!-- Memorize the token who is using this command -->
[h: TokenId = currentToken()]

<!-- Change the current token to the travel one, so that its properties can be used -->
[h: switchToken(ChosenTravel)]

<!-- Teleport -->
[h: moveTokenToMap(TokenId, MapDestination, Xdestination, Ydestination, Zdestination)]

3) To the PC token, add the travel macro with this code:

Code: Select all

[macro("Travelling@Lib:Whatever"): ""]
4) Keep the PC token within reach of a travel token and try.

EDIT
Don't ask me why I didn't think of it earlier, but instead of creating four properties you can just create a single one that, as a json object, will hold all four values, and if you put some work in it also multiple destinations, but that's something that depends on how you want to structurate the thing.
"There are many ways my Son, to find where the souls of Demons remain...
But it takes only one second of despair and of doubt until, at last, your Soul they will gain..."

User avatar
Altrunchen
Giant
Posts: 135
Joined: Sun Dec 02, 2012 3:01 pm

Re: Impersonation Errors with MoveTokenToMap()

Post by Altrunchen »

Irrlicht wrote:Alright, I've tested this and it works; as said above, the only difference with th original intent is that the travel macro is among a token's own macros, rather than in the travel token itself.

1) Create a new set of token properties in the campaign properties window; call it "Travel" or whatever you want, and add these properties:

Xdestination:1
Ydestination:1
Zdestination:1
MapDestination:None

2) Create one (or more) travel tokens. Their names will need to ALWAYS start with the same word or words; here I chose to have them start with "Travel to" (their full names being "Travel to Forest", "Travel to Cellar", and such).
For these tokens set the group of properties to "Travel", the one you just created. Now, for each of these tokens, edit the coordinates and target map (manually or by making a macro for that purpose).

3) Assuming you don't already have a library token, create one (drag a token to the Hidden layer, set it to "NPC" and "Visible to Players") and name it Lib:Whatever. Create a new macro in its panel, call it "Travelling", and add to it the following code:

Code: Select all

<!-- Get names of all tokens on map -->
[h: Names = getTokenNames()]

<!-- Make a list of the actual travel tokens present -->
[h: TravelTokens = ""]
[h, foreach(Name, Names), code:
{
[IsTravel = startsWith(Name, "Travel")]
[if(IsTravel == 1): TravelTokens = listAppend(TravelTokens, Name)]
}]

<!-- Reduce the above list to the tokens within 5 feet from the player who used the macro; of course you can set a greater reach or remove it entirely -->
[h: AvailableTravels = ""]
[h, foreach(Token, TravelTokens), code:
{
[Distance = getDistance(Token)]
[if(Distance <= 5): AvailableTravels = listAppend(AvailableTravels, Token)]
}]

<!-- Prompt choice among travel tokens in reach -->
[h: status = input(
"ChosenTravel|" + AvailableTravels + "|Available Locations|LIST|VALUE=STRING"
)]

[h: abort(status)]

<!-- Memorize the token who is using this command -->
[h: TokenId = currentToken()]

<!-- Change the current token to the travel one, so that its properties can be used -->
[h: switchToken(ChosenTravel)]

<!-- Teleport -->
[h: moveTokenToMap(TokenId, MapDestination, Xdestination, Ydestination, Zdestination)]

3) To the PC token, add the travel macro with this code:

Code: Select all

[macro("Travelling@Lib:Whatever"): ""]
4) Keep the PC token within reach of a travel token and try.

EDIT
Don't ask me why I didn't think of it earlier, but instead of creating four properties you can just create a single one that, as a json object, will hold all four values, and if you put some work in it also multiple destinations, but that's something that depends on how you want to structurate the thing.
Wow thanks for the help! But let me see if I understand this. So there's no way to get it so that a player can click on a token and then run a macro that affects their impersonated token? At least not without storing the names into a json list or using library tokens or even custom properties? Are you sure there is absolutely no bypass for this? I mean I kind of like the idea of being able to have specifically mapped travel tokens that anyone can select and use without having to worry about proximity to other tokens or having to dramatically change the structure of the framework. So it's really an issue that can only be bypassed with library tokens, additional properties or PC-token based macros? There isn't some kind of alternative? :s

But if there isn't any other way to do this then I thank you for the help. Now I just have to figure out how to make json objects @_@.
Image

User avatar
Altrunchen
Giant
Posts: 135
Joined: Sun Dec 02, 2012 3:01 pm

Re: Impersonation Errors with MoveTokenToMap()

Post by Altrunchen »

I got it! Now I just have to fine-tune it so that it's more of the currently impersonated one perhaps. Here's the code:

Code: Select all

<!-- Get current map name-->
[h: ThisMap = getCurrentMapName()]

<!--Get list of all maps-->
[h: MapList = getAllMapNames()]

<!--Get rid of the current map name from the list of maps-->
[h: ThisMapIndex = listFind(MapList, ThisMap)]
[h: MapList = listDelete(MapList, ThisMapIndex)]

<!--Sort the list of maps-->
[h: MapList = listSort(MapList, 'A')]

<!-- Prompt User for target map -->
[h:status = input(
"TargetMap|"+MapList+"|Which Map is this character going to?|LIST|SELECT = 0 VALUE = STRING")]
[h:abort(status)]

<!--Get destination on target map-->
[h: Xcoord = 1]
[h: Ycoord = 1]
[h: Zcoord = 1]

<!--Get the list of tokens to specify the token to move-->
[h: cond = '{"pc":1, "owned":1}']
[h: ids = getTokens("json", cond)]

<!--Move Token to destination-->
[t: moveTokenToMap( ids, TargetMap, Xcoord, Ycoord, Zcoord)]
Image

Post Reply

Return to “Macros”