Skip to content

Instantly share code, notes, and snippets.

@Bastlifa
Last active August 19, 2020 04:08
Show Gist options
  • Save Bastlifa/0fb83ccd7d1039851b72e472b2178ec3 to your computer and use it in GitHub Desktop.
Save Bastlifa/0fb83ccd7d1039851b72e472b2178ec3 to your computer and use it in GitHub Desktop.
Druid Shift Script for Roll20 D&D 5E OGL Sheet
/**************************************** Druid Shift ****************************************
This is for the 5E OGL sheet in Roll20. It will probably not work with any others without
some modification. Also, I didn't do much in the way of error checking.
The GM must make character named Druid X, where X is the creature being shifted into.
It is suggested that the GM duplicate existing creatures, rename them, and assign to the druid
player. The images for the characters must be uploaded and assigned to the avatar of the druid
form characters. The easiest way I've found it to open the character sheet, edit, right click
the picture in the avatar, copy, paste into your image program, save, upload and put it back in.
Maybe you could just upload it back into the avatar directly. Anyways, this won't work if you
don't first upload the image to your library.
Either the druid player should have a general macro, or the forms characters should
each have a token action with the body !DSBaseChar
It's helpful if the druid character has token actions for each desired form.
If you use multiple druids, or shapeshifters, add another check for !DSCharName for them.
I put in several example forms in the code. Delete or add as needed.
In the !DSBaseChar part of the code, you must replace 'Druid Char Name' with
'<the druid character's name, exactly>'.
If you want to do custom creatures, and not bother updating the API script, do the following:
Make and assign a character, such as Camel, and name it Druid Camel
Have player enter this command: !DSCustom,Camel,Large,0
That's commas with no spaces, first item is for the api to know which command to deal with,
second is the creature (it'll add the Druid to the Camel, so just enter the creature's base name),
third is creature size, last is darkvision range.
*********************************************************************************************/
on("ready", function() {
var getCleanImgsrc = function (imgsrc) {
var parts = imgsrc.match(/(.*\/images\/.*)(thumb|med|original|max)([^\?]*)(\?[^?]+)?$/);
if(parts) {
return parts[1]+'thumb'+parts[3]+(parts[4]?parts[4]:`?${Math.round(Math.random()*9999999)}`);
}
return;
};
on("chat:message", function (msg) {
// Make sure to copy your druid character's name exactly in CharacterGet parameter.
if (msg.type === "api" && msg.content === "!DSBaseChar") {
CharacterGet('Druid Char Name', msg, 'Normal', 0);
}
if (msg.type === "api" && msg.content === "!DSCaveBear") {
CharacterGet('Druid Cave Bear', msg, 'Large', 60);
}
if (msg.type === "api" && msg.content === "!DSAllosaurus") {
CharacterGet('Druid Allosaurus', msg, 'Large', 0);
}
if (msg.type === "api" && msg.content === "!DSCrocodile") {
CharacterGet('Druid Crocodile', msg, 'Large', 0);
}
if (msg.type === "api" && msg.content === "!DSDireWolf") {
CharacterGet('Druid Dire Wolf', msg, 'Large', 0);
}
if (msg.type === "api" && msg.content === "!DSGiantSpider") {
CharacterGet('Druid Giant Spider', msg, 'Large', 60);
}
if (msg.type === "api" && msg.content === "!DSGiantToad") {
CharacterGet('Druid Giant Toad', msg, 'Large', 30);
}
if (msg.type === "api" && msg.content.split(',')[0] === "!DSCustom") {
let parts = msg.content.split(',')
let creatureName = parts[1]
let creatureSize = parts[2]
let creatureDV = parts[3]
CharacterGet(`Druid ${creatureName}`, msg, `${creatureSize}`, Number(creatureDV))
if (!findObjs({_type: 'macro', _playerid: msg.playerid, name: creatureName})[0])
{
createObj('macro', {
name: creatureName,
playerid: msg.playerid,
istokenaction: false,
visibleto: "",
action: msg.content
});
}
}
});
function Size(charSize, msg)
{
if (charSize === "Normal"){
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set("height", 70);
getObj(o._type,o._id).set("width", 70);
});}
if (charSize === "Large"){
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set("height", 140);
getObj(o._type,o._id).set("width", 140);
});}
if (charSize === "Huge"){
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set("height", 210);
getObj(o._type,o._id).set("width", 210);
});}
if (charSize === "Gargantuan"){
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set("height", 280);
getObj(o._type,o._id).set("width", 280);
});}
}
function CharacterGet(characterName, msg, charSize, darkvision)
{
if (!msg.selected || !getObj(msg.selected[0]._type,msg.selected[0]._id).get('represents'))
{
sendChat('Druid Shift Script', 'Please select a representative token to shift');
return;
}
var ShiftCharacter = findObjs({ type: 'character', name: characterName })[0];
if (!ShiftCharacter)
{
sendChat('Druid Shift API', `No character found: ${characterName}`);
return;
}
//sendChat("", "ShiftChar is: " + ShiftCharacter.get('name'));
if(getAttrByName(ShiftCharacter.get('id'), 'npc', 'current') == 1)
{
//sendChat("", "NPC thing happened");
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set({
imgsrc: getCleanImgsrc(ShiftCharacter.get('avatar')),
bar1_link: 'None',
represents: ShiftCharacter.id,
bar1_value: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
bar1_max: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
bar2_link: 'None',
bar2_value: getAttrByName(ShiftCharacter.get('id'), 'npc_ac', 'current'),
light_radius: darkvision,
light_dimradius: 0,
light_otherplayers: false
});
});
}
else
{
//sendChat("", "PC thing happened");
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set({
imgsrc: getCleanImgsrc(ShiftCharacter.get('avatar')),
represents: ShiftCharacter.id,
bar1_value: getAttrByName(ShiftCharacter.get('id'), "hp", 'current'),
bar1_max: getAttrByName(ShiftCharacter.get('id'), "hp", 'max'),
bar1_link: findObjs({type: "attribute", characterid: ShiftCharacter.get('id'), name: 'hp'})[0].id,
bar2_value: getAttrByName(ShiftCharacter.get('id'), 'ac', 'current'),
bar2_link: findObjs({type: "attribute", characterid: ShiftCharacter.get('id'), name: 'ac'})[0].id,
light_radius: darkvision,
light_dimradius: 0,
light_otherplayers: false
});
});
}
Size(charSize, msg);
}
});
/w Einin &{template:npcaction} {{name=Shift}} {{rname=Forms}} {{description=[Einin Form &#x1F9DD](!DSBaseChar)
**Furry**
[Cave Bear &#x1F43B](!DSCaveBear)
[Dire Wolf &#x1F43A](!DSDireWolf)
[Displacer Beast](!DSDisplacerBeast)
**Feathered**
[Giant Eagle &#x1F985](!DSGiantEagle)
[Giant Vulture &#x1F424](!DSGiantVulture)
[Griffon](!DSGriffon)
[Owlbear &#x1F989](!DSOwlbear)
**Chitinous**
[Giant Spider &#x1F577](!DSGiantSpider)
[Giant Scorpion &#x1F982](!DSGiantScorpion)
**Scaled**
[Crocodile &#x1F40A](!DSCrocoile)
[Allosaurus &#x1F996](!DSAllosaurus)
[Giant Toad &#x1F438](!DSGiantToad)
**Elemental**
[Earth Elemental &#x1F30E](!DSEarthElemental)
[Air Elemental &#x1F32A](!DSAirElemental)
[Fire Elemental &#x1F525](!DSFireElemental)
[Water Elemental &#x1F30A](!DSWaterElemental)
}}
@malloki
Copy link

malloki commented May 9, 2018

I set this up in my campaign and it is kicking back an error and shutting down my API. The Error is:

TypeError: Cannot read property 'substring' of undefined
TypeError: Cannot read property 'substring' of undefined
at TrackedObj.validateAttrs (/home/node/d20-api-server/api.js:878:26)
at TrackedObj.set (/home/node/d20-api-server/api.js:968:18)
at apiscript.js:3708:43
at Function.
.each._.forEach (/home/node/d20-api-server/node_modules/underscore/underscore.js:182:9)
at CharacterGet (apiscript.js:3707:19)
at apiscript.js:3631:13
at eval (eval at (/home/node/d20-api-server/api.js:151:1), :65:16)
at Object.publish (eval at (/home/node/d20-api-server/api.js:151:1), :70:8)
at /home/node/d20-api-server/api.js:1634:12
at `/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560

@bradroeger
Copy link

I don't know if you are still having this problem but, I had the same problem with a Hunter Shark. There was a problem with the token I deleted it from the character sheet created a brand new one and then it worked.

@bjornevik
Copy link

bjornevik commented Apr 9, 2020

I don't know if you are still having this problem but, I had the same problem with a Hunter Shark. There was a problem with the token I deleted it from the character sheet created a brand new one and then it worked.

Despite this comment being over a year old at this point:
Had this exact problem myself, you fix it by uploading an avatar to roll20, you cannot use an external source or the marketplace.

If you're wondering why, it's due to roll20's imgsrc and avatar property restrictions, as specified in https://wiki.roll20.net/API:Objects#imgsrc_and_avatar_property_restrictions

@Bastlifa
Copy link
Author

Bastlifa commented Apr 9, 2020

Huh, I guess I didn't see these. Yeah, Bjornevik, I used to do that (it's in the comments at the top of the script), but then I thought roll20 changed something, and that restriction went away (IIRC, I was able to use imgsrc that I hadn't uploaded). Then more recently, someone had it break with a copied campaign, which I believe he fixed by deleting and recreating the character for the shifting form (e.g., deleting Druid Bear, and dragging out a new Bear, renaming it). I have no idea why that's the fix for it, but maybe it helps.

@zebbzebb
Copy link

zebbzebb commented Apr 19, 2020

Instead of this macro script, I used the script below in the abilities of my druid for a query of the forms he can use as a token action.

!?{Wich Wildshape?|AnimalOne,DSAnimalOne|AnimalTwo,DSAnimalTwo|...|LastAnimal,DSLastAnimal}

it is important not having any blank spaces!

and for all the different shapes I put this in abilities

!DSNameOfCharacter

@BlueWolfX8
Copy link

BlueWolfX8 commented Apr 22, 2020

@Bastlifa Could you show an example in the API of how to add in a second druid or shape shifter?

And does anyone know what to add to get the Token instead of the character picture?

@zebbzebb
Copy link

zebbzebb commented Apr 22, 2020

@BlueWolfX8
instead of:

if (msg.type === "api" && msg.content === "!DSBaseChar")  {
            CharacterGet('Druid Char Name', msg, 'Normal', 0);
}

Write

if (msg.type === "api" && msg.content === "!DSDruidOneName")  {
            CharacterGet('Druid One Name', msg, 'Normal', 0);
}
if (msg.type === "api" && msg.content === "!DSDruidTwoName")  {
            CharacterGet('Druid Two Name', msg, 'Normal', 0);
}

I use the code as-is and get the token with all its references

@Bastlifa
Copy link
Author

Yeah, Zebb's got it.

As for different token and avatar pictures, probably would have to reference default token somehow...
Might be easier to just put your druids token images in a rollable table, and reference the images in there.
I could be less lazy, and see what the json of the default token looks like in order to try and get the imgsrc from it... and maybe someday I will :)

@BlueWolfX8
Copy link

@BlueWolfX8
instead of:

if (msg.type === "api" && msg.content === "!DSBaseChar")  {
            CharacterGet('Druid Char Name', msg, 'Normal', 0);
}

Write

if (msg.type === "api" && msg.content === "!DSDruidOneName")  {
            CharacterGet('Druid One Name', msg, 'Normal', 0);
}
if (msg.type === "api" && msg.content === "!DSDruidTwoName")  {
            CharacterGet('Druid Two Name', msg, 'Normal', 0);
}

I use the code as-is and get the token with all its references

Thanks ZebbZebb! I will try that!

@BlueWolfX8
Copy link

Yeah, Zebb's got it.

As for different token and avatar pictures, probably would have to reference default token somehow...
Might be easier to just put your druids token images in a rollable table, and reference the images in there.
I could be less lazy, and see what the json of the default token looks like in order to try and get the imgsrc from it... and maybe someday I will :)

LOL, its all good. I didn't know if anyone else had that same question!

@Bastlifa
Copy link
Author

BTW, mixed results on whether you have to download and re-upload the avatars. I have it in the script comments that you do, and IIRC, you originally had to. I just tried it today without uploading the avatar though, and it worked, but another person I was talking to tried it and it gave an error. He changed to the uploaded avatar, and it worked. I'm not sure why mine worked, and his didn't, but if you get an error, try uploading the NPC avatar.

@Fmerrick
Copy link

This script works great! Thanks so much! But I have a quick question I'll bet one of you can answer. I am trying to mod the script so it pulls in both the creature's AC, for Bar 2, and speed, for Bar 1. I really don't know the programming on this, I'm just copying the bar1_value lines and putting in the correct attribute name. It works beautifully when I pull in the creature and switch between creatures, but when I try to switch back to the Base Character, it then takes the values from the last creature and inserts them in the character sheet for the druid. How do I get it to leave the PC character sheet alone and just show whatever values were there originally?

@Fmerrick
Copy link

This script works great! Thanks so much! But I have a quick question I'll bet one of you can answer. I am trying to mod the script so it pulls in both the creature's AC, for Bar 2, and speed, for Bar 1. I really don't know the programming on this, I'm just copying the bar1_value lines and putting in the correct attribute name. It works beautifully when I pull in the creature and switch between creatures, but when I try to switch back to the Base Character, it then takes the values from the last creature and inserts them in the character sheet for the druid. How do I get it to leave the PC character sheet alone and just show whatever values were there originally?

I found your script that added in AC, I just added duplicate lines to include speed. Works perfectly, thanks!

@vtt-lair
Copy link

For anyone else unsure how to update the AC and get the changes: when changing to the NPC character, set

bar2_link: 'None'

and then set the AC using:

bar2_value: getAttrByName(ShiftCharacter.get('id'), 'ac', 'current'),

Then when you set it back to the PC token, reset the link and value:

bar2_value: getAttrByName(ShiftCharacter.get('id'), 'ac', 'current'),
bar2_link: findObjs({type: "attribute", characterid: ShiftCharacter.get('id'), name: 'ac'})[0].id,

@Tsiaug
Copy link

Tsiaug commented Apr 30, 2020

Instead of this macro script, I used the script below in the abilities of my druid for a query of the forms he can use as a token action.

!?{Wich Wildshape?|AnimalOne,DSAnimalOne|AnimalTwo,DSAnimalTwo|...|LastAnimal,DSLastAnimal}

it is important not having any blank spaces!

and for all the different shapes I put this in abilities

!DSNameOfCharacter

Hey there! Thanks for the amazing job! I'm new into Roll20 and I'm trying to set up these lines you guys have written.
I need to say that I need a bit more of help as I'm not an experienced coder.
I have already written the API Script and later this macro that shows me the table that @Bastifla wrote above.

I'm just missing how to link in the chat form box that pops up when I click on my Shapeshifting macro, that my Druid character needs to turn into that Wolf I want her to shape into after clicking over the name with the beast icon.
The name that needs to be written is the Journal name of the beast? As in.

[Wolf Form &#x1F43A](!DSWolfForm)

Being WolfForm the name in the journal of that creature.

I'm a bit lost here, all help is appreciated!

@Bastlifa
Copy link
Author

Bastlifa commented Apr 30, 2020

I'm just missing how to link in the chat form box that pops up when I click on my Shapeshifting macro, that my Druid character needs to turn into that Wolf I want her to shape into after clicking over the name with the beast icon.

Not quite sure what you mean here, but the general idea is:
1: [Wolf Form &#x1F43A](!DSWolfForm) will make an api call with msg.content === !DSWolfForm
2: should your api have something like this:

if (msg.type === "api" && msg.content === "!DSWolfForm")  {
            CharacterGet('WolfForm', msg, 'Large', 0);
}

your command will have the effect of changing the selected tokens to the wolf form, and linking the token to that sheet. (selected is important).

Basically, there's some setup for the script itself. The command is what msg.content is, while the CharacterGet name is the name of the journal entry.

@kniraven
Copy link

kniraven commented May 4, 2020

Hey there!
No issues so far, just wanted to say this is awesome and thank you.

@Bastlifa
Copy link
Author

Bastlifa commented May 4, 2020

NP, ty.

@Cata1ystC1oud
Copy link

Yo, this script is great, nothing else out there does the job. Currently I'm trying to figure out how to integrate new shapes less painfully than altering the api directly.

Does anyone know of a way to write to the api from a macro? Or another api that does this that I can repurpose code from? I'm looking go at this from two angles

  1. to have a prompt for new shape name, size, darkvision values, activated by a macro that calls an api to write to DruidShift.js
  2. to then have DruidShift.js update an existing macro with the new command to change shape. I know that CarryTokens can write to a macro.

@Bastlifa
Copy link
Author

Bastlifa commented May 15, 2020

Hey Cata1ystC1oud, as far as I know, you can't write to the API from in-game, but you are correct that the api can write to in-game macros.

Maybe a simple custom input could work, I'll try something here in a sec, will update with a custom input method.

To use a custom input, do the following (for example):

Have a character named Druid Camel assigned to the player
Have player enter (or use macro with body of)
!DSCustom,Camel,Large,0

Splitting on commas, since animals may have 2-word names (cave bear). Also, no spaces is important in the api call for customs.

Edit: Entering a custom druid shift will now create the macro for the player, so they can just enter it once from the chat, and it should add it to their collection. (if this behavior is undesired, just remove the code from 75-84)

@Fmerrick
Copy link

Fmerrick commented May 27, 2020 via email

@Darkcritop
Copy link

Darkcritop commented May 31, 2020

Hi! I have some issues with the code. My caracters are link : Bar 3 hp, Bar 2 Passifwisdom and Bar 1 AC. Then i change the bar in the script :
bar2_link: 'none',
represents: ShiftCharacter.id,
bar2_value: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
bar2_max: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
Then i can see the Hp remaining of the caracter in Bar :3 and in Bar 1 i see the Hp of the animal wildshape instead of the passifwisdom.

1 Issue : Ac remain of the caracter and not the npc druid animal he turn into.
2 Issue : When i turn back caracter, Bar 2 is link to none now and keep track of remains HP/Max hp of the creature and Bar 1 is now link to HP instead of AC.
3 Issue : Caracter now lose Darkvision (She a Elf) in Advanced parameter.

Thank for help ( i am french sorry haha)

I let you a exemple of the code i got here : I try multiple Shifter and it work but got the same issue with both. If someone could send the code i need i would be gratefull! No programmer skill by the way ! Just a DM trying to have the best tools for his players.

/**************************************** Druid Shift ****************************************
This is for the 5E OGL sheet in Roll20. It will probably not work with any others without
some modification. Also, I didn't do much in the way of error checking.

The GM must make character named Druid X, where X is the creature being shifted into.
It is suggested that the GM duplicate existing creatures, rename them, and assign to the druid
player. The images for the characters must be uploaded and assigned to the avatar of the druid
form characters. The easiest way I've found it to open the character sheet, edit, right click
the picture in the avatar, copy, paste into your image program, save, upload and put it back in.
Maybe you could just upload it back into the avatar directly. Anyways, this won't work if you
don't first upload the image to your library.

Either the druid player should have a general macro, or the forms characters should
each have a token action with the body !DSBaseChar

It's helpful if the druid character has token actions for each desired form.

If you use multiple druids, or shapeshifters, add another check for !DSCharName for them.

I put in several example forms in the code. Delete or add as needed.

In the !DSBaseChar part of the code, you must replace 'Druid Char Name' with
'<the druid character's name, exactly>'.

If you want to do custom creatures, and not bother updating the API script, do the following:

Make and assign a character, such as Camel, and name it Druid Camel
Have player enter this command: !DSCustom,Camel,Large,0
That's commas with no spaces, first item is for the api to know which command to deal with,
second is the creature (it'll add the Druid to the Camel, so just enter the creature's base name),
third is creature size, last is darkvision range.

*********************************************************************************************/

on("ready", function() {

var getCleanImgsrc = function (imgsrc) {
    var parts = imgsrc.match(/(.*\/images\/.*)(thumb|med|original|max)([^\?]*)(\?[^?]+)?$/);
    if(parts) {
        return parts[1]+'thumb'+parts[3]+(parts[4]?parts[4]:`?${Math.round(Math.random()*9999999)}`);
    }
    return;
};

on("chat:message", function (msg) {
    // Make sure to copy your druid character's name exactly in CharacterGet parameter.
    if (msg.type === "api" && msg.content === "!DSMae")  {
        CharacterGet('Mae', msg, 'Normal', 0);

}
if (msg.type === "api" && msg.content === "!DSAcolyte") {
CharacterGet('Acolyte', msg, 'Normal', 0);
}
if (msg.type === "api" && msg.content === "!DSGiantHyena") {
CharacterGet('Druid Giant Hyena', msg, 'Large', 0);
}
if (msg.type === "api" && msg.content === "!DSCaveBear") {
CharacterGet('Druid Cave Bear', msg, 'Large', 60);
}
if (msg.type === "api" && msg.content === "!DSAllosaurus") {
CharacterGet('Druid Allosaurus', msg, 'Large', 0);
}
if (msg.type === "api" && msg.content === "!DSCrocodile") {
CharacterGet('Druid Crocodile', msg, 'Large', 0);
}
if (msg.type === "api" && msg.content === "!DSDireWolf") {
CharacterGet('Druid Dire Wolf', msg, 'Large', 0);
}
if (msg.type === "api" && msg.content === "!DSGiantSpider") {
CharacterGet('Druid Giant Spider', msg, 'Large', 60);
}
if (msg.type === "api" && msg.content === "!DSGiantToad") {
CharacterGet('Druid Giant Toad', msg, 'Large', 30);
}
if (msg.type === "api" && msg.content === "!DSHyena") {
CharacterGet('Druid Hyena', msg, 'Normal', 0);
}
if (msg.type === "api" && msg.content.split(',')[0] === "!DSCustom") {
let parts = msg.content.split(',')
let creatureName = parts[1]
let creatureSize = parts[2]
let creatureDV = parts[3]
CharacterGet(Druid ${creatureName}, msg, ${creatureSize}, Number(creatureDV))
if (!findObjs({_type: 'macro', _playerid: msg.playerid, name: creatureName})[0])
{
createObj('macro', {
name: creatureName,
playerid: msg.playerid,
istokenaction: false,
visibleto: "",
action: msg.content
});
}
}

});



function Size(charSize, msg)
{


if (charSize === "Normal"){
    _.each(msg.selected,function (o) {
        getObj(o._type,o._id).set("height", 70);
        getObj(o._type,o._id).set("width", 70);
        
    });}
    
    if (charSize === "Large"){
    _.each(msg.selected,function (o) {
        getObj(o._type,o._id).set("height", 140);
        getObj(o._type,o._id).set("width", 140);
        
    });}
    
    if (charSize === "Huge"){
    _.each(msg.selected,function (o) {
        getObj(o._type,o._id).set("height", 210);
        getObj(o._type,o._id).set("width", 210);
        
    });}
    
    if (charSize === "Gargantuan"){
    _.each(msg.selected,function (o) {
        getObj(o._type,o._id).set("height", 280);
        getObj(o._type,o._id).set("width", 280);
        
    });}
}

function CharacterGet(characterName, msg, charSize, darkvision)
{
var ShiftCharacter = findObjs({ type: 'character', name: characterName })[0];
//sendChat("", "ShiftChar is: " + ShiftCharacter.get('name'));
if(getAttrByName(ShiftCharacter.get('id'), 'npc', 'current') == 1)
{
//sendChat("", "NPC thing happened");
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set({
imgsrc: getCleanImgsrc(ShiftCharacter.get('avatar')),
bar2_link: 'none',
represents: ShiftCharacter.id,
bar2_value: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
bar2_max: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
light_radius: darkvision,
light_dimradius: 0,
light_otherplayers: false
});
});
}
else
{
//sendChat("", "PC thing happened");
_.each(msg.selected,function (o) {
getObj(o._type,o._id).set({
imgsrc: getCleanImgsrc(ShiftCharacter.get('avatar')),
represents: ShiftCharacter.id,
bar1_value: getAttrByName(ShiftCharacter.get('id'), "hp", 'current'),
bar1_max: getAttrByName(ShiftCharacter.get('id'), "hp", 'max'),
bar1_link: findObjs({type: "attribute", characterid: ShiftCharacter.get('id'), name: 'hp'})[0].id,
light_radius: darkvision,
light_dimradius: 0,
light_otherplayers: false
});
});
}

    Size(charSize, msg);
}

});

@Bastlifa
Copy link
Author

Hmm, I wonder why I never had it change AC... It seems like an obvious thing to do. I'll put up the new one, after this comment, with some error checking as well because of errors I ran into. As usual, just change the bars, or remove sections, if you like things in different bars.

Also, I haven't messed around with advanced dynamic lighting, except for a bit on the dev server, because I kept hearing about how it caused a lot of problems for people, so I'll put off working on that.

For Darkcritop, maybe I'll look at advanced dynamic lighting another time, but for bars at least, the CharacterGet function should be something like:

function CharacterGet(characterName, msg, charSize, darkvision)
    {
        if (!msg.selected || !getObj(msg.selected[0]._type,msg.selected[0]._id).get('represents'))
        {
            sendChat('Druid Shift Script', 'Please select a representative token to shift');
            return;
        }
        var ShiftCharacter = findObjs({ type: 'character', name: characterName })[0];
        if (!ShiftCharacter)
        {
            sendChat('Druid Shift API', `No character found: ${characterName}`);
            return;
        }
        //sendChat("", "ShiftChar is: " + ShiftCharacter.get('name'));
            if(getAttrByName(ShiftCharacter.get('id'), 'npc', 'current') == 1)
            {
                //sendChat("", "NPC thing happened");
                _.each(msg.selected,function (o) {
                    getObj(o._type,o._id).set({
                        imgsrc: getCleanImgsrc(ShiftCharacter.get('avatar')),
                        bar3_link: 'None',
                        represents: ShiftCharacter.id,
                        bar3_value: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
                        bar3_max: getAttrByName(ShiftCharacter.get('id'), 'hp', 'max'),
                        bar1_link: 'None',
                        bar1_value: getAttrByName(ShiftCharacter.get('id'), 'npc_ac', 'current'),
                        bar2_link: 'None',
                        bar2_value: Number(getAttrByName(ShiftCharacter.get('id'), 'npc_perception', 'current')) + 10,
                        light_radius: darkvision,
                        light_dimradius: 0,
                        light_otherplayers: false
                    });
                });
            }
            else
            {   
                //sendChat("", "PC thing happened");
                _.each(msg.selected,function (o) {
                    getObj(o._type,o._id).set({
                        imgsrc: getCleanImgsrc(ShiftCharacter.get('avatar')),
                        represents: ShiftCharacter.id,
                        bar3_value: getAttrByName(ShiftCharacter.get('id'), "hp", 'current'),
                        bar3_max: getAttrByName(ShiftCharacter.get('id'), "hp", 'max'),
                        bar3_link: findObjs({type: "attribute", characterid: ShiftCharacter.get('id'), name: 'hp'})[0].id,
                        bar1_value: getAttrByName(ShiftCharacter.get('id'), 'ac', 'current'),
                        bar1_link: findObjs({type: "attribute", characterid: ShiftCharacter.get('id'), name: 'ac'})[0].id,
                        bar2_value: getAttrByName(ShiftCharacter.get('id'), 'passive_wisdom', 'current'),
                        bar2_link: findObjs({type: "attribute", characterid: ShiftCharacter.get('id'), name: 'passive_wisdom'})[0].id,
                        light_radius: darkvision,
                        light_dimradius: 0,
                        light_otherplayers: false
                    });
                });
            }
        
    
        Size(charSize, msg);
    }

I think, for some reason, PC sheets use passive_wisdom for passive perception, but for NPCs, it's different. Cave Bear, for example, has 11 passive wisdom, but 3 perception bonus.

@Darkcritop
Copy link

Thx a million time ! It work great! I have a bit of trouble with the perception code. The code was crashing until i delete only that part. Perception still the same has caracter but i don't mind at all. Thx again!

bar2_link: 'None',
bar2_value: Number(getAttrByName(ShiftCharacter.get('id'), 'npc_perception', 'current')) + 10,

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment