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

Need Architecture Advice for API Script

I'm looking for advice on how to architect the following functionality. I don't need specific code per se. I'm instead looking for advice on the best (good enough?) way to assemble/architect all the pieces. I feel I have enough coding experience to be able to bang all the bits into place, but I'd like advice on how to assemble it all in the best way, keeping in mind possible extensibility. Any advice is appreciated and THANK YOU in advance. I'm building a tactical combat simulator in Roll20. Each combatant is represented by a character sheet and a linked token on the map. At intervals, players will work off the initiative order to declare targets for any/each of their weapons. All weapons are ranged  weapons, listed in a repeating list on their character sheet. Each weapon may be targeted at a different opponent. Players with higher initiative declare their targets after those with lower initiative. The chance to hit any given target is based on the target's range (in hexes) and a firing table. The latter determines the odds of a hit at each range as well as the maximum range for a possible hit.  After all targets are declared, fire is simultaneous.   Here's what I'm thinking the API script should do: The player targets each weapon by clicking a 'target' button in each attack's repeating row on the character sheet. The button click triggers the API script. The API script works off the field data from the character's repeating row. This contains the firing chart designation (represented by a single letter). The script asks(?) the player to select the target for the attack. [ What's the best way to get this info? ] The script determines the range based on the position of the character's token and the target's token. The script then determines the attack's to-hit number from both the attack's firing chart and the range to the target. An attack ChatMenu.js string is generated. This will contain other repeating row field names and values, such as weapon name, damage, etc. This string will be saved  to the character sheet in a hidden field. The name of the target's token will also be displayed in the attack's repeating row, for the player to reference. After all players have declared all their attacks, in game terms, fire is then conducted simultaneously. This is accomplished by each player working through their list of targeted attacks and rolling the attacks one at a time in any order they prefer. To accomplish this, each player clicks a 'fire' button  in each targeted attack's repeating row on the character sheet. This then sends the above generated ChatMenu.js string to the Chat, the attack die is rolled, and the sheet's roll template takes care of the rest. Questions: What's the best way to architect this? Are there better ways to do it than my pseudo-architecture above? What are some of the key architectural elements needed, in the sheet, the API, etc.?
1760405051

Edited 1760405173
timmaugh
Forum Champion
API Scripter
One note on gameplay before I make suggestions about structure... If you're creating this system (and therefore have some flexibility), can I suggest regarding the attacks either some sort of "cycle" mechanic (i.e., a reload or cool down period before the weapon can be fired again) and/or a "bandwidth" mechanic (requiring the player to allocate their offensive capacity... not every weapon can be fired every turn... i.e., this weapons platform can output 100pts of attack per turn, and the user has to decide how to divide that between weapons that require different amounts)? The purpose being that if every turn is "everyone fires everything" then the only tension is reducible to who rolls better and how many bad guys are on the field. On the other hand, a cycle mechanic and/or a bandwidth mechanic creates the requirement of strategic planning and a risk/reward structure to the player's own agency. IOW, the player feels like they can contribute to their chances of winning. Also, a note on script + API integration... It's generally suggested, when you're building a sheet, to not require a script in order to play the system if you're going to release the sheet/script publicly since only Pro users will be able to start a game that can fully implement both (scripts being a Pro perk). However, for some of the things you want to do (that will also survive the process of incorporating suggestions from experienced sheet devs and script devs), you are likely going to be in the realm of requiring a script. For instance, a sheet dev can correct me if I'm wrong about this, but sheets can't determine range between tokens. OK, all that said, here's my general feedback... 1) Targets are (probably) going to have to be gathered via Roll20 @{target} syntax... which means a command line that triggers a message that needs to be caught and parsed... which means a script. That command is going to have to be USER INITIATED. If you want to understand why, you can watch the first 15 min of  this video  (or watch the whole thing if you want to understand metascripts). That means your process will probably be to send a command to the chat (either from the sheet or be having the sheet send a button to the chat output that the user then clicks on), the command line is set to be picked up by your script but prompts the user along the way for the targeted token. 2) You keep mentioning ChatMenu.js... which I'm guessing refers to a script named that? (guessing because there isn't one in the one-click repo that is named that, so maybe this was a bit of code your saved off of the forum/discord somewhere...?) Chat menus can be made without a script, and those menus can even include buttons that fire commands which trigger scripts to run. The vehicle for this is a character sheet template, so since you're already building the sheet (it sounds like), you can do a lot to control the look of the presentation just by building the template the way you want, then populating it with lines and information and buttons to control the various actions you need to incorporate. Bottom line: building a dependency on your own script is already putting you into niche territory; I would suggest *against* also relying on someone else's chat-menu-producing script. That code might change (if it does come from the 1-click) or other people might have it installed but a different/newer version. Either construct your layout as your own template stored in your sheet, or build your script in such a way that it can construct the layout on the fly. 3) YMMV, but I don't like storing ephemeral information in the character sheet. The sheet is for character (or, in this case, weapon platform) data. Separate from that, you have data connected to the fight (really just the turn). Again, it might be just me, but I don't like storing that sort of information in the sheet. My preference would be to share the confirmation of targeting-per-system to a chat menu. The overall flow (imagining a cycle and/or bandwidth mechanic involved, too) I would see would be something like...: ...weapon systems are "enabled" (for inclusion in the attack) on the sheet via a checkbox ...when the Turn Order event is detected, a script checks every player-controlled character sheet and decrements every weapon's "cycle" counter by 1 (or whatever metric). Maybe a weapon can fire once every 5 rounds, so when it fires it gets a "5" in this field. On every Turn Order event, that number is decremented until it reaches "0" and the weapon is ready to be fired again. ...that same code handling the Turn Order change event can now send a whispered message to each sheet controller alerting them to the status of their weapons (enabled, available, or unavailable (cycling) for X more rounds). Each row is a weapon system, and that row has a button to handle enabling/disabling a system for inclusion in the next attack (changing the value on the sheet). The user can configure what is enabled (and the script can report if the amount of attack comes in under the bandwidth limit, if you employ such a mechanic). The script can even monitor (using the messages these button clicks would generate) whether the player is under the bandwidth for the attack so that the targeting phase can begin. The total bandwidth would be those weapon systems that are both enabled AND which sit at "0" as their cycle value (e.g., they are not "reloading"). At the end of the enable/disable phase, the player clicks a "Ready" button. ...the resulting message is a chat button ("Attack!") pre-prepped to be ready to ask for targeting information for each enabled weapon system. If the sheet had four weapon systems enabled, each system would a target designation portion of the line. Maybe the script has already read that System A takes a single target (one targeting statement), while System B can target two (2 targeting statements). The user clicks this button and answers the target requests. ...the resulting message consults the appropriate chart, does the distance calculation, and rolls for damage, presenting it all in a public chat of the results. What you should notice about this approach is that the only data that needs to be tracked/changed on the character sheet is whether the system is enabled or not and how much longer it might be in a "cycle/reload" state. Everything else is handled through chat, tracking the ID of the weapon system in the command line, and passing that back to the script answering the message. Since the only 2 things changing are the "enabled" and "cycle" values, if you don't implement either of these mechanics, you don't even have to worry about this part! The point is, all of the ephemera of the targeting, etc., need not be stored on the sheet. In fact, there are many people who don't like to use a sheet -- especially those who only have a single monitor and limited screen real estate. These are just some random thoughts based on what you posted. If you have any questions or if something wasn't clear, just post back and I'll try to explain more.
1760452604

Edited 1760452789
First of all, thank you for the thoughtful reply. I really appreciate it!  If you're creating this system (and therefore have some flexibility)... The game system is FASA's Star Trek: Starship Tactical Combat Simulator , a game was last updated in the late 1980s but has survived on the internet over the decades. It has mechanics for power allocation to ships systems (including weapons) and then a 3-phase-per-turn mechanic for movement, targeting, and weapons fire. It's generally suggested, when you're building a sheet, to not require a script in order to play the system if you're going to release the sheet/script publicly This sheet is not intended for public release . I have a long-time group of RPG/Wargamers, and we decided to give ST:STCS a go. I am very open to "working outside the box" to get this done. Targets are (probably) going to have to be gathered via Roll20 @{target} I was thinking of having the player select the target token on the map and then click a "targeted" checkbox on the weapon repeating item to fire off an API targeting script. The script could get the object info in that manner. The name of the targeted ship would then be displayed in a text field in the weapon row to confirm the selection. This is also when the range to target and to-hit number would be calculated and saved to the hidden field. Possibly some trigonometry to determine which target hex-side is impacted (which determines shield defense and damage chart selection) Repeat for each weapon. Then move to the next player in initiative order. You keep mentioning ChatMenu.js... Ah, yes, this is GiGs awesome Universal Chat Menus script I found in the forums. IMO, it allows me to easily output very nice tabular formats to represent data. Again, since this sheet isn't intended for public consumption... I don't like storing ephemeral information in the character sheet I appreciate this and myself don't like the idea of inserting the upcoming roll data in a hidden field. However, since firing each weapon comes later, it would (IMO) simplify everything greatly if the roll is "pre-created", stored on the sheet, and then sent to Chat at the appropriate time (when an action button is clicked). The Chat script would roll the attack die, determine hit location, and a roll-template would take care of the rest. - I'm still open to further analysis and consideration on this approach... I'll add to this thread as I begin implementation in case you or anyone else is interested and/or has additional thoughts. I'm trying to learn as I go and appreciate the input! (And I know my players do, too!)
1760457302

Edited 1760468738
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
My advice would be to do this all (or nearly all) within the sheet itself. With the exception of automatically determining range, all of this can be done within the character sheet itself. Doing it in the sheet instead of outsourcing it to an API script makes your code base unified and more reliable because you don't need to worry that the API server has crashed on you. Here's a rough outline of how I'd handle each of your goals via the character sheet: The player targets each weapon by clicking a 'target' button in each attack's repeating row on the character sheet. This target button would be an action button that triggers a sheetworker on the sheet. This is the entry point into the functionality, and would be one of only a few interactions the player would need to make with the sheet. Successful resolution of all the steps that follow would then result in this weapon being marked as "targeted". The button click triggers the API script. The API script  sheetworker works off the field data from the character's repeating row. This contains the firing chart designation (represented by a single letter). The script  sheetworker asks(?) the player to select the target for the attack. [ What's the best way to get this info? ] I'd recommend using the data query trick discovered by Oosh in his Adventures with StartRoll forum post. The startRoll call would look a little something like: const targetQuery = await startRoll('!{{target=[[0[response=@{target|character_name}]]]}}'); //extract the character name from the roll object The script determines the range based on the position of the character's token and the target's token. The script then determines the attack's to-hit number from both the attack's firing chart and the range to the target. The sheet would prompt the user for the distance to the target via a roll query sent via startRoll using the same technique demonstrated above, replacing @{target|character_name} with a roll query. It can then determine the to hit number based on the firing chart contained within the sheet. This is the one piece that would require an API script to fully automate. However, you are almost certainly going to need the same amount of user input even with an API script, as you'll need to handle the edge case of their being two tokens for a given firing ship on the map at the same time, and so would need to have the user target the firing ship in addition to the targeted ship. Personally, there's not much difference between that user input and asking them to input the distance. An attack ChatMenu.js string is generated. This will contain other repeating row field names and values, such as weapon name, damage, etc. This string will be  saved  to the character sheet in a hidden field. The name of the target's token will also be displayed in the attack's repeating row, for the player to reference. After all players have declared all their attacks, in game terms, fire is then conducted simultaneously. This is accomplished by each player working through their list of targeted attacks and rolling the attacks one at a time in any order they prefer. To accomplish this, each player clicks a 'fire' button  in each targeted attack's repeating row on the character sheet. This then sends the above generated ChatMenu.js string to the Chat, the attack die is rolled, and the sheet's roll template takes care of the rest The sheet would finally output a chat message using a roll template that is part of the sheet. The roll template would be styled to present the information as you want. ADVANCED ADDITIONAL SOLUTION: If you wanted to go more advanced, you could pretty much fully automate the resolution of the firings by having he character sheet have a different display mode, "combat tracker". Create a character sheet that you set to this display mode. You'd then use the cross sheet communication capability made possible by startRoll to pass the firing information for each ship and weapon to this tracker sheet. It would then have a button on it that you could click once all targeting decisions have been made to simultaneously output all the attack resolutions in a single chat message. This button could also utilize the cross sheet communication to tell each sheet to switch the weapons back to being untargeted. EDIT: To Tim's point about doing things without needing the character sheet opened, creating all of this sheet side instead of API side actually makes that easier as a user that wants that functionality just needs to create a custom ability on the character and call the ability button for the weapon; the sheet then handles all the rest and any updates you do are automatically propagated to any token actions that have been made; as opposed to an API call which would likely require additional command syntax to be added to the macros.