Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

Making a Charactermancer for my own system

Hi community, I'm a programmer and web developer and have toyed in the past with building a Charactermancer for my own d20 system, called "CRE8". I think it would really help the system go through playtesting and be adopted by other players like nothing else. At this point, rather than program my own GUI, I'm thinking of using the tools that already come with my Roll20 Pro subscription! But I'm sure I'll have lots of questions. So I'm starting one thread where all my questions can go, rather than spamming the forum with lots of micro-topics. Thanks for letting me take space on this forum, and thanks especially to those who take time to read my questions and send me in the right directions. Who knows, once I know what I'm doing, maybe I'll even be able to give back to the community by answering others' questions.
QUESTION 1) Is the fact that my system isn't a widespread system with its own entry in the Compendium going to hurt my project in the long run?
QUESTION 2) Need help debugging JavaScript! I have a function that mines an object full of bonuses and penalties from various sources, and returns the final total modifier. I'm console.logging the input parameter to this function, and the console shows that its value is indeed an empty object {}. However, when I immediately after use Object.keys on the object and console.log the result, the output is an array ["0", "1"]. That's not how Object.keys() is supposed to work! What is going on here? Furthermore, next I put the Object.keys() output into a foreach() function. The console is giving an error here, saying that bonusTypes.foreach is not a function. Huh? foreach not a function of an array ["0", "1"]?
1586960323

Edited 1586960534
McKay B.
KS Backer
OK, I think I got (Question 2) worked out. First half: ["0", "1"] is what you get when you take Object.keys("{}") -- the keys of a string . So I'll have to make my object/attributes valid JSON strings and use JSON.parse() on them before processing them. Second half: Apparently roll20 sheets are picky about using forEach instead of foreach. That's a shame, since it's an area of JavaScript where I'm used to being lazy. Hopefully these help some other programmers down the line.
1586960802
Caden
Forum Champion
Sheet Author
API Scripter
Compendium Curator
forEach should work fine. I use it all over the place.
QUESTION 3) In my system, there are cascading effects of stats. For example, XP determines Level, which helps determine Caster Level, which helps determine Spellcraft Check. When the user types a new value into the XP input, it triggers a Sheet Worker Script that updates Level. Now, as far as I've figured out so far, the Sheet Worker Script also has to be a MASSIVE function that manually updates everything else that depends on Level. Is there a way to compartmentalize all the cascading changes, so that I can write much smaller functions?' Ideally, if I could set up a listener that will notice Level being changed by the first Sheet Worker Script, and will call a resultant Sheet Worker Script that can update everything that depends directly on level (like Caster Level). Then have a listener for Caster Level changing that will run a Sheet Worker Script to update Spellcraft Check. So far, my attempts to code this cascading system are not working. I read that chains of asynchronous calls are not desirable as a best practice, but it seems worthwhile to me to make the code much  cleaner and easier to read.
1586975129
GiGs
Pro
Sheet Author
API Scripter
You'd be best off creating separate threads for specific questions. People willing to help out on coding issues dont really care what the game system you're designing is (it might be great! it's just not relevant for the question), all we want to know are some relevant specifics about the problem you want solving. But to this specific question: McKay B. said: In my system, there are cascading effects of stats. For example, XP determines Level, which helps determine Caster Level, which helps determine Spellcraft Check. When the user types a new value into the XP input, it triggers a Sheet Worker Script that updates Level. Now, as far as I've figured out so far, the Sheet Worker Script also has to be a MASSIVE function that manually updates everything else that depends on Level. Is there a way to compartmentalize all the cascading changes, so that I can write much smaller functions?' Ideally, if I could set up a listener that will notice Level being changed by the first Sheet Worker Script, and will call a resultant Sheet Worker Script that can update everything that depends directly on level (like Caster Level). Then have a listener for Caster Level changing that will run a Sheet Worker Script to update Spellcraft Check. So far, my attempts to code this cascading system are not working. I read that chains of asynchronous calls are not desirable as a best practice, but it seems worthwhile to me to make the code much  cleaner and easier to read. Generally speaking, it is by far more efficient to do a massive sheet worker that updates everything relevant for a stat. But also this does eventually lead to putting everything in a single sheet worker, which can be tricky to code. Having separate sheet workers to handle different elements, is much easier to code, but if your sheet gets really big, it can cause lag. So there's always a trade off. If you think things through carefully, you can make the cascade method work pretty well for most sheets. But you do need to think about how you can keep the number of cascades down: minimise the total number of getAttrs and setAttrs calls (as they are the things which slow things down) as much as you can. It's a lot more efficient to do one getAttrs call that reads a hundred attributes and does all the necessary math for them, then it is to have 100 separate getAttrs calls.
1586975311
GiGs
Pro
Sheet Author
API Scripter
McKay B. said: QUESTION 1) Is the fact that my system isn't a widespread system with its own entry in the Compendium going to hurt my project in the long run? I believe the charactermancer does require you to have a compendium selected for your game-  you dont need to actually use anything from the compendium, just have one selected.
1586975533

Edited 1586975557
GiGs
Pro
Sheet Author
API Scripter
McKay B. said: QUESTION 2) Need help debugging JavaScript! I have a function that mines an object full of bonuses and penalties from various sources, and returns the final total modifier. I'm console.logging the input parameter to this function, and the console shows that its value is indeed an empty object {}. However, when I immediately after use Object.keys on the object and console.log the result, the output is an array ["0", "1"]. That's not how Object.keys() is supposed to work! What is going on here? Furthermore, next I put the Object.keys() output into a foreach() function. The console is giving an error here, saying that bonusTypes.foreach is not a function. Huh? foreach not a function of an array ["0", "1"]? You wont get very good answers to questions like these, unless you supply the actual code you used, so we know exactly what is going on. (And yes, foreach won't work - you need to be very precise about case.) Note that the objects are not JSON objects, they are javascript objects. They look like JSON objects for simple data, but they are much more permissive on what you include in them and have slightly different syntax.
GiGs said: You'd be best off creating separate threads for specific questions. People willing to help out on coding issues dont really care what the game system you're designing is (it might be great! it's just not relevant for the question), all we want to know are some relevant specifics about the problem you want solving. But to this specific question: Generally speaking, it is by far more efficient to do a massive sheet worker that updates everything relevant for a stat. But also this does eventually lead to putting everything in a single sheet worker, which can be tricky to code. Having separate sheet workers to handle different elements, is much easier to code, but if your sheet gets really big, it can cause lag. So there's always a trade off. If you think things through carefully, you can make the cascade method work pretty well for most sheets. But you do need to think about how you can keep the number of cascades down: minimise the total number of getAttrs and setAttrs calls (as they are the things which slow things down) as much as you can. It's a lot more efficient to do one getAttrs call that reads a hundred attributes and does all the necessary math for them, then it is to have 100 separate getAttrs calls. OK then, I'll create bunches of threads if that's what you tell me to do! I just didn't want to hog the forum. So there is  a way to make sheet workers chain-react? If so, how?
GiGs said: I believe the charactermancer does require you to have a compendium selected for your game-  you dont need to actually use anything from the compendium, just have one selected. OK, but I can supply information about my system's feats, etc., without pulling them from a Compendium? I've seen databases mentioned in passing in a few threads of this forum. Can you essentially build your own Compendium if you get good at linking to a database?
GiGs said: You wont get very good answers to questions like these, unless you supply the actual code you used, so we know exactly what is going on. (And yes, foreach won't work - you need to be very precise about case.) Note that the objects are not JSON objects, they are javascript objects. They look like JSON objects for simple data, but they are much more permissive on what you include in them and have slightly different syntax. Thanks for the tips. I know JSONs and JavaScript objects are different, but since I was struggling to store information in my Character Sheet in a form other than strings, I was thinking I would need to convert objects to actual JSONs in order to make them work. But maybe that's only a problem because I was trying to initialize default values for character attributes. Is there a way to make a default value be an object rather than a string?