RPTools / maptool

Virtual Tabletop for playing roleplaying games with remote players or face to face.
http://rptools.net
GNU Affero General Public License v3.0
790 stars 257 forks source link

There should be a way to "fully" render a token (bars, states, etc) in frames and dialogs #2328

Open kwvanderlinde opened 3 years ago

kwvanderlinde commented 3 years ago

Is your feature request related to a problem? Please describe. It seems there are only two places where tokens can be rendered with their state and bars: on the map and in the initiative window. There is no way to render the token with its state inside of a custom frame, at least not with fidelity to the state configuration.

Describe the solution you'd like There could be a new token function that returns an asset URL to the composite token image. Using it would be as simple as:

<img src='[r: getCompositeTokenImage(50, "token id")]'>

Describe alternatives you've considered An alternative would be to add more state and bar functions until the desired functionality can be replicated. This would require more work when writing the HTML. On the other hand, a composite image wouldn't need to actually exist, and these more granular functions could be useful in their right. I think we would basically need these for it to work:

Additional context This is an example of what I'm talking about in terms of a "composite" image used on the map and in the initiative window: image image Contrast this with the bare token image: image

kwvanderlinde commented 3 years ago

There was some discussion on discord about what the syntax to use for the resulting asset URLs. I'll summarize and expand here, and also give my understanding of some pros and cons.

My initial (unexpressed) thought was that an opaque URL could be generated (e.g., asset://abcdefghijklmnopqrstuvwxyz123456). As a pro, This would mean a static URL for a given token, so HTML would not have to be altered to reflect the state changes (it would have to be re-rendered still). That seems like a pretty niche benefit, though. The biggest con here would seem to be the inflexibility of the URL to support multiple variations, as it would require persisting an image for each variation, or at least persisting the information required to build the image corresponding to the URL. It would also prevent URL hacking, which would be unfortunate IMO.

The syntax proposed by @Azhrei was a URL parameterized with a query string. E.g., asset://xxxx?width=##&states=xxx+xxx+xxx&bars=bar-name-1:50+bar-name-2:35 (this also includes his suggested alternative to the "-## hack"). The nice thing about this syntax is that it is very flexible. The requested image can easily be built on-demand (with intelligent caching, optionally) without requiring any persistence of images or other lookup tables that an opaque URL would require. The only real(?) downside is that the URL needs to be updated to reflect any state changes. I don't actually think this point matters much since HTML generally needs to be updated in order reflect changes from outside a frame. And if we get a good way to push data into frames from the outside, then the frame can be updated easily. So I'd say there are no real downsides to this approach.

Regardless of the exact syntax chosen for the URL, there should be a function that can produce these URLs. Macro writers would almost always call the function rather than build their own URLs. So what should such function call should look like? What should it be named? What should the macro writer have to provide to get the desired results? Should the macro writer have to lookup the token states and bars and then pass them into the function? Or should the function look these up based on the token ID passed to it? Should the function even operate on tokens, or should it operate on image assets? Personally, I would like the simplest call to be the use case of completely rendering the token:

getCompositeTokenImage("token id")

Variations (with/without certain bars and states) could be supported by adding (JSON?) parameters after the token ID:

getCompositeTokenImage("token id", json.set("",
    "width", 50,
    "states", json.append("", "bloodied", "prone"),
    "bars", json.set("", "hp", 50, "temp_hp", 10)
))
Azhrei commented 3 years ago

Variations (with/without certain bars and states) could be supported by adding (JSON?) parameters after the token ID:

getCompositeTokenImage("token id", json.set("",
    "width", 50,
    "states", json.append("", "bloodied", "prone"),
    "bars", json.set("", "hp", 50, "temp_hp", 10)
))

This seems reasonable, although I might abstract the width as a subelement of another property (maybe "portrait" or "token") since states and bars are both categories with subelements...