#3D Polymorph

1 messages ยท Page 1 of 1 (latest)

fair salmon
#

@floral swan

floral swan
#

thx

minor rapids
floral swan
#

that is target? i thought target is the actor that you drag onto the actor you want transformed?

minor rapids
#

..you may be right

#

then we do want to modify the data but we can not update it as it's just an object so manual setting it is

#
Hooks.on("dnd5e.transformActor", (actor, target, data, options) => {
  let 3dmodel = target.data.token.getFlag("levels-3d-preview","model3d");
  if (3dmodel){
    data.token["levels-3d-preview"].model3d = 3dmodel
  }
});
floral swan
#

so as the actor is temporary we are sure it is unlinked

#

correct?

#

which is why we are allowed to use data.token

minor rapids
#

um no?

minor rapids
#

or an actor

#

it's an object

runic sage
#
/**
     * A hook event that fires just before the actor is transformed.
     * @function dnd5e.transformActor
     * @memberof hookEvents
     * @param {Actor5e} actor                  The original actor before transformation.
     * @param {Actor5e} target                 The target actor into which to transform.
     * @param {object} data                    The data that will be used to create the new transformed actor.
     * @param {TransformationOptions} options  Options that determine how the transformation is performed.
     */
minor rapids
#

@floral swan do you want the model of the original actor or the model of the target?

#

because that might need to be swtiched

floral swan
minor rapids
#

ye

floral swan
#

i want to polymorph it to the target, as if I dont switch anything up, it currently takes the actors model as base value anyways

minor rapids
#

gotcha

#

I still think you need to modify the resultant token not just the prototype of the created actor

floral swan
#

(which looks pretty funny as it can appear to change in size by quite a bit if the polymorphed creature is alot bigger. so same model just scaled)

#

hmmm... how would i get access to the resultant token through the hook?

minor rapids
#

I don't think you can

floral swan
#

i mean. I can probably set a temporary flag and scan everything for the flag

minor rapids
#

ye

floral swan
#

but that would be really inefficient

minor rapids
#

tiem to log the hooks

floral swan
#

but are you sure that it isnt enough to set the prototypes model?

minor rapids
#

try it

floral swan
#

will do

#

target.data.token always works?

minor rapids
#

What I expect to currently happen is that you normally set the flag on the prototype, this makes a token with that flag which is then used to display the model

If you update an actor you aren't changing the token hence the image doesn't change

minor rapids
floral swan
#

aah okay

minor rapids
#

target.token is the token for unlinked tokens, and null for linked ones

floral swan
#

so in general just always use target.data.token to be safe?

minor rapids
#

?

#

If you want the prototype sure. But you usually want the token

#

not the prototype

floral swan
#

ahhh

#

sorry.

minor rapids
#

All good

floral swan
#

hmm

#

seemingly doesnt work at all

minor rapids
#

I have an idea htough

#

Hacky idea to modify the resultant token, has the potential to break if multiple people are doing it:

Hooks.on("dnd5e.transformActor", (actor, target, data, options) => {
  let 3dmodel = target.data.token.getFlag("levels-3d-preview","model3d");
  if (!3dmodel) return
   foundry.utils.setProperty(data.token, "flags.levels-3d-preview.model3d", 3dmodel); //modify the prototype of the resultant actor
  Hooks.once("preUpdateToken",(tokenDoc,changes,context,userID)=>{ // Hook onto the next token update (since dnd5e updates the regular image) and update the flags of the resultant token doc to have the model
    tokenDoc.data.update({"flags.levels-3d-preview.model3d":3dmodel}) // document.data.update is only a client side change but since we are hooking onto preUpdate, ergo before the doc is updated this is what we need.
  })
});
floral swan
#
  let 3dmodel = target.data.token.getFlag("levels-3d-preview","model3d");
  if (3dmodel){
    data.token["levels-3d-preview"].model3d = 3dmodel;
  }
  console.log("polymorph log");
});```
does not even display polymorph log in the console
runic sage
#

That's gonna error

#
foundry.utils.setProperty(data.token, "flags.levels-3d-preview.model3d", 3dmodel);
minor rapids
runic sage
#

All of them ๐Ÿ™‚

minor rapids
#

oh right

#

ffs

#

wait no why?

runic sage
#

.token["levels-3d-preview"] undefined?

#

also, flags.

minor rapids
#

Ah that line. Yeah I don't think it's even needed

#

included for good measures

floral swan
#

what does it say if the console.log("polymorph log") never appears in the console?

minor rapids
floral swan
#

ooooh

minor rapids
#

Actually updates the token

#

well

#

changes the data of the next updated token's update which is nearly guaranteed to be the relevant one

floral swan
#

breaks if multiple people are doing it at the same time?

#

or at all?

runic sage
#

Could use Hooks.on and Hooks.off... ๐Ÿ˜„ or be smart and use preUpdate

minor rapids
#

so it executes client side

#

and there's no such issue

minor rapids
#

Either way I expect this to function

floral swan
#

is the original program also a client?

minor rapids
#

?

floral swan
#

I'm selfhosting, so if I as gm use it, it works the same way?

minor rapids
#

oh, urgh

#

I did not consider that

#

transformActor doesn't pass the user id either...

#

Okay yeah no idea

#

I suppose we could make the entire thing gm only

runic sage
#

Get the active player owner, if any?

minor rapids
#

and then regular update

#
Hooks.on("dnd5e.transformActor", (actor, target, data, options) => {
  if (!game.user.isGM) return
  let my3dmodel = target.data.token["levels-3d-preview"].model3d
  if (!my3dmodel) return
   foundry.utils.setProperty(data.token, "flags.levels-3d-preview.model3d", my3dmodel); //modify the prototype of the resultant actor
  Hooks.once("updateToken",(tokenDoc,changes,context,userID)=>{ // Hook onto the next token update (since dnd5e updates the regular image) and update the flags of the resultant token doc to have the model
    tokenDoc.setFlag("levels-3d-preview","model3d",my3dmodel)
  })
});
#

This should work

floral swan
#

what does gm only mean in this context?

runic sage
#

(game.user)

minor rapids
#

unless you have multiple gms at which point I'll probably just give up ๐Ÿ˜…

floral swan
#

ah. but the info gets pushed to all clients afterwards anyways

#

naaaah

minor rapids
minor rapids
minor rapids
#

I don't think there's a way around that though

runic sage
#

(Hooks.on / off)

#

and lots of filtering

minor rapids
#

(ping me if there's an issue going back to studying otherwise)

floral swan
#

@minor rapids okay, now i am confused. seemingly the world script doesnt even fire

#

i did a console.log right below the Hooks.on, and can see no log

minor rapids
#

Scroll way up

#

yep syntax error

#

interesting

floral swan
#

where do you find the syntax error?

minor rapids
#

in the console

floral swan
#

ah. i reloaded, then it came

#

first time, the console already seemed too full and cut it

minor rapids
#

Welp I don't see it

floral swan
#

what does Uncaught SyntaxError: Unexpected strict mode reserved word mean?

minor rapids
#

using a reserved word somehwere

#

might be 3dmodel?

#

Aha!

#

TIL

floral swan
#

that is a javascript internal word? o.O

minor rapids
#

now I have an errant comma...

#

apparently

runic sage
#

Variable names starting with a number...?

minor rapids
#

oh

floral swan
#

oh that could be

minor rapids
#

Do you see the errant comma / missing bracket?

#

Because I don't

#

oh ffs

#

curlys

#

Alright fixed!

floral swan
#

maybe its the {}

#

in the setflag

minor rapids
#

๐Ÿ˜›

floral swan
#

damn ๐Ÿ˜„

minor rapids
#

But yeah fixed the syntax stuff

#

Check the updated version

floral swan
#

but hey, atleast i noticed it aswell^^

floral swan
#

@minor rapids still does not console.log

#

but has no error anymore

minor rapids
#

Unable to replicate but it does error

floral swan
#

it does? o.O

minor rapids
#

Works!

#

Actually let me put in more safety

#

Yep works

#
Hooks.on("dnd5e.transformActor", (actor, target, data, options) => {
  console.log("transformed")
  if (!game.user.isGM) return
  let my3dmodel = target.data.token["levels-3d-preview"]?.model3d
  if (!my3dmodel) return console.log("Could not find model")
   foundry.utils.setProperty(data.token, "flags.levels-3d-preview.model3d", my3dmodel); //modify the prototype of the resultant actor
  Hooks.once("updateToken",(tokenDoc,changes,context,userID)=>{ // Hook onto the next token update (since dnd5e updates the regular image) and update the flags of the resultant token doc to have the model
    tokenDoc.setFlag("levels-3d-preview","model3d",my3dmodel)
  })
});
#

This gets to yelling at me about the model not being found which makes sense since I don't have 3dcanvas

#

Steps to reproduce. Put as an active worldscript, reload to refresh the code, transform an actor, see the console.log triggering -> works until then

floral swan
#

active worldscript means " esmodules": ["./polymorph.js"], in case that the script is called polymorph.js in the main folder of the world, right?

minor rapids
#

I haven't messed with my world.json in a while but yeah that looks correct

#

Make sure you save your file after editing it^^

floral swan
#

i did. otherwise i couldnt have had the 3dmodel error aswell

#

so i'm pretty sure that part is correct

minor rapids
#

Well I am unsure what to tell you as it seems to function as well as possible on my end

floral swan
#

oh. what would happen if other modules might use the same hook?

minor rapids
#

works fine

#

Literally every script based module uses hooks in some capacity. If you couldn't share them nothing would work

floral swan
#

@minor rapids which foundry version are you on? I'm still using v9 as quite a few modules arent upgraded to v10 yet

#

maybe it has something to do with that

minor rapids
#

Also v9

#

Let me update my 5e to be doubly safe

#

Same result as before

#

If you aren't even getting the first console.log() your worldscript isn't loaded

runic sage
#

Wait, where is the log?

minor rapids
#

In the hook

runic sage
#

Ah, goodie

minor rapids
#

@floral swan Have you restarted foundry yet? json changes are only registered on restart

#

Okay yeah I can reproduce the previously mentioned behaviour (getting the console.log on actor transform) with 0 modules and the foundry and dnd5e version posted above so it works for as much as I can test

floral swan
#

currently restarting

floral swan
#

I deactivated all the modules except 3dcanvas and still cannot find the log. it definitely loads though as I did also test it with a console.log before the hook, and that is displayed

#

3dcanvas+dependencies

runic sage
#

Logged in as GM, I assume?

floral swan
#

as gm, on the client itself. maybe i should try to log in as a player via browser

minor rapids
#

(also testing as a gm btw)

floral swan
#

ooooh

#

so there is a difference between dragging it from the tokens character sheet and the general actors character sheet

minor rapids
#

there is?

#

hu

floral swan
#

first one does nothing

minor rapids
#

I mean yeah you need to trigger a transform

floral swan
#

yeah, but i thought in order to transform a token, one would rather drag it to the tokens character sheet

minor rapids
#

so does it work?

floral swan
#

it says it couldnt find the model

minor rapids
#

damnit

floral swan
#

on the actor. and does nothing when executed on the token

minor rapids
#
Hooks.on("dnd5e.transformActor", (actor, target, data, options) => {
  console.log("transformed")
  if (!game.user.isGM) return
  let my3dmodel = foundry.utils.getProperty(target.data.token,"flags.levels-3d-preview.model3d")
  if (!my3dmodel) return console.log("Could not find model")
   foundry.utils.setProperty(data.token, "flags.levels-3d-preview.model3d", my3dmodel); //modify the prototype of the resultant actor
  Hooks.once("updateToken",(tokenDoc,changes,context,userID)=>{ // Hook onto the next token update (since dnd5e updates the regular image) and update the flags of the resultant token doc to have the model
    tokenDoc.setFlag("levels-3d-preview","model3d",my3dmodel)
  })
});
#

Try this?

#

if that still can't find the model my only guess is that the flag path is incorrect which I can't check

runic sage
#

Is target.data.token defined?

minor rapids
runic sage
#

Ah no you right, it's an actor

#

It doesn't have the flag then

minor rapids
#

target.data.token is very much defined for me

minor rapids
minor rapids
runic sage
#

Did you try console.log(target) to make sure it's all there?

minor rapids
#

I just logged target.data.token on my end

#

and it is the expected prototype token

#

Code used to test:

Hooks.on("dnd5e.transformActor", (actor, target, data, options) => {
  console.log("transformed")
  console.log(target.data.token)
  if (!game.user.isGM) return
  let my3dmodel = foundry.utils.getProperty(target.data.token,"flags.levels-3d-preview.model3d")
  if (!my3dmodel) return console.log("Could not find model")
   foundry.utils.setProperty(data.token, "flags.levels-3d-preview.model3d", my3dmodel); //modify the prototype of the resultant actor
});
floral swan
#

so. the current thing is as follows: if i execute it on the actor sheet, it creates a new polymorphed actor sheet, and if i drag that to the scene, it works

minor rapids
#

That makes sense as we are updating the prototype

#

so the Hooks.once isn't working

#

Or rather not modifying the relevant token

floral swan
#

rather not triggering at all

#

as in that case, the "transformed" log is also nowhere to be found

minor rapids
#

And considering we don't have access to the resultant actor I don't think I can fix this

floral swan
#

but wouldnt console.log still trigger?

minor rapids
#

which?

floral swan
#

console.log("transformed")

minor rapids
#

if that isn't triggering then your worldscript isn't triggering which brings up back to the previous point of an incorrectly setup worldscript

floral swan
#

or does "transformActor" actually never happen in terms of hooking when using a token?

minor rapids
#

If you actually transform an actor the hook should fire

floral swan
#

if you use the sheet from a token

#

the hook seemingly doesnt trigger

runic sage
#

The function that transforms the actor is the also the one calling the hooks in this case. If one happen, they should both happen.

minor rapids
#

dnd5e transformation only works for linked actors if that is what you mean

floral swan
#

oooooh. npcs cant polymorph?

fair salmon
#

the restore only works on linked

minor rapids
#

Right but the hook doesn't fire either badger

#

just tested it

fair salmon
#

but, take a very very close look at the order of operations inside the function itself:

    Hooks.callAll("dnd5e.transformActor", this, target, d, {
      keepPhysical, keepMental, keepSaves, keepSkills, mergeSaves, mergeSkills,
      keepClass, keepFeats, keepSpells, keepItems, keepBio, keepVision, transformTokens
    });

    // Create new Actor with transformed data
    const newActor = await this.constructor.create(d, {renderSheet: true});

    // Update placed Token instances
    if ( !transformTokens ) return;
    const tokens = this.getActiveTokens(true);
    const updates = tokens.map(t => {
      const newTokenData = foundry.utils.deepClone(d.prototypeToken);
      newTokenData._id = t.id;
      newTokenData.actorId = newActor.id;
      newTokenData.actorLink = true;
      return newTokenData;
    });
    return canvas.scene?.updateEmbeddedDocuments("Token", updates);
minor rapids
#

oh that's useful

fair salmon
#

so, hook is called, where you can modify any data that is about to be produced, then the actor is created after that, then IF we are transforming the token, the token update is fired after that with predefined token data from d.prototypeToken

minor rapids
#

So it should work correctly no need for token update calls

minor rapids
#

provided the hook fires which only happens for linked actors

#

yep hook does not fire for unlinked tokens

floral swan
#

is that a bug or is that intentional?

fair salmon
#

ok i see, yea, just above this call --

    // Update unlinked Tokens in place since they can simply be re-dropped from the base actor
    if ( this.isToken ) {
      const tokenData = d.prototypeToken;
      delete d.prototypeToken;
      tokenData.actorData = d;
      return this.token.update(tokenData);
    }
minor rapids
fair salmon
#

so if its unlinked, the token is simply updated with new stuff (since we can't revert it)

minor rapids
#

which is the isuse here

fair salmon
#

yes, i was just confirming that myself ๐Ÿ‘

minor rapids
#

Right so my job here is done then

#

The prototype update apparently works if I understood the comment correctly, hooking onto unlinked transform ain't doable so the script works as well as it can

fair salmon
#

d.flags.dnd5e.isPolymorphed = true;

#

you can probably have an update token hook monitoring for unlinked token updates which set that value on the instanced actor

#

which would be in its actorData

minor rapids
#

I don't have access to the target token then though

#

which makes that a moot point as we don't know what data to set

fair salmon
#

target token? that is the token being updated, right?

minor rapids
#

target is the actor we update TO

#

we want the prototype token settings of that actor

#

to get the value we need to set on the new token

#

so if I drag a bear on a druid the bear is the target

fair salmon
#

ok, so that should be present in the actor link update for the token?

#

nooo, because it wouldnt change the source actor, that's the whole point of the unlinked nonsense

minor rapids
#

yep

#

SOoooooooo

#

@floral swan sorry for the non-ideal solution can't think of a better way and I would like to be done with this chapter by midnight so Imma peace out

floral swan
#

I totally understand

#

thx for the help

fair salmon
#

you could always get REAL ballsy and use the experimental warpgate "powermorph" approach

floral swan
#

that does what? ๐Ÿ˜„

fair salmon
#

but...that's kind of like saying that we can fix your car's issues by just having you drive in reverse

#

technically a solution, but probably not what the goal was, lol

floral swan
#

okay ^^

fair salmon
minor rapids
fair salmon
#

one day i'll get around to writing a warpgate based replacement

#

one day

minor rapids
#

Honestly the next step here would be to submit a PR with better morphing but that's a multiple days project

floral swan
#

๐Ÿ˜„

minor rapids
#

In case you were wondering what I am doing rn:

#

But yeah have a nice evening folks

fair salmon
#

ah, calculating dnd5e AOE shapes

#

makes sense

#

lol

minor rapids
#

let's go with that

floral swan
#

there is one more interesting thing I noticed

#

restore transformation does not take into account the height of a token, which in a 3d map means said tokens clips into the ground

minor rapids
#

there is no hook for transformation reversion

floral swan
#

oooof

minor rapids
#

So you are out of luck there

floral swan
#

open a github issue about respecting height? or is there a reason why it isnt considered?

minor rapids
#

Next step here is the aforementioned PR or wrapping the transformation function in a module, likely using libwrapper. Also a multi day project

floral swan
#

oh right

minor rapids
#

and other flags might not want to be reverted

floral swan
#

height isnt core

minor rapids
#

So 3 options

#

In order of effort for you

floral swan
#

sometimes i forget that height itself isnt core.

minor rapids
#
  1. make a pr with better transformation logic directly to the repo (insanely complex ask @fair salmon he knows)
  2. Make a module to wrap the transformation function to do what you want. Still a multi day project but doable
  3. Yell at Kindly ask ripper to make a new module that deals with this
fair salmon
#
  1. Tune the experimental powermorph script to your use-case needs and use that will full control ๐Ÿ™‚
minor rapids
#

hmm I'd swap this with point 3

#

to keep the order of complexity

#

okay damn it I need to get this done. Quitting discord for now

floral swan
#

Kindly ask ripper to make a new module that deals with this
He understandibly wont open this can of worms as all systems want their own polymorph handling then

runic sage
#

What a journey. ๐Ÿฟ

floral swan
#

๐Ÿ˜„

#

i hope my incompetence was amusing at least

#

thx for the help

fair salmon
#

this group's general lack of familiarity with ripper mods didnt help

runic sage
#

and the fact that we never use the polymorpher because warpgate.

floral swan
#

you polymorph with the powermorph script or what?

runic sage
#

Made my own. ๐Ÿ˜Ž

floral swan
#

so everyone here has his/her own polymorph script? ๐Ÿ˜„

#

should also start writing one for good measures then

runic sage
#

My use case is a bit special. I got a wizard who likes to cast polymorph, but I don't want a lot of actors in the sidebar. So I wrote a script to get actor data from a compendium, just by inputting a name, and did a whole lotta shenanigans to make it work without destroying the target actor. Recommended? Not at all. Works flawlessly? You betcha.

#

It's "only" 55 lines

fair salmon
#

not bad, powermorph v3 is just over 100

runic sage
#

Oh it's both mutate and polymorph ๐Ÿ™‚

#

Luckily I don't have a druid, I haven't made a default config for it for wildshape.

minor rapids
minor rapids
runic sage
#

Back to your books. ๐Ÿงน

minor rapids
runic sage
#

or no dinner

floral swan
#

๐Ÿ˜„ ๐Ÿ˜„ ๐Ÿ˜„

minor rapids
#

Also I am done now

#

But yes Zhell isn't the best person to ask when you wonder how many custom things you should write

#

Perspective might be a little skewed there ๐Ÿ˜› ๐Ÿ˜‰

runic sage
#

If I didn't write it myself, how can I trust it

floral swan
#

I already wrote quite a few sequencer macros for making 2d animations for most of my spells (atleast all those that are too complex for automated animations). I am currently thinking about doing the same for 3d particle animations for the 10% of scenes where I provide 3d maps

#

still not 100% convinced of the effort to value ratio

minor rapids
#

oh for animations? the ratio is fucking awful

#

doesn't stop me though

floral swan
#

3d particle macros that only get used in 10% of the maps (i will still use 2d 80-90% of the time as making all maps 3d is just unfeasible work if you actually also want to play dnd) might be even worse value^^

floral swan
#

@fair salmon where does powermorph store the original actor data to restore it?

fair salmon
#

on the token's actor

plush lion
#

i just now saw this thread, even though i followed @floral swan efforts in my server: a couple of notes:
@fair salmon what needs to be done, in a nutshell, is transfer the flags from the polymorph token to the polymorphed token bacuse 3DC uses it's own flag for the token 3d model

Also, ELEVATION is a core field, if Pholymorphing is resetting that it should be definatelly be handled by core dnd5e and an issue should be opened. You are confusing token height (wall height) with Elevation here i think

#

Transfering flags during a polymorph could also be a reasonable feature request

brittle fulcrum
#

<insert necromancy art>