Guide to Initiative Events: Difference between revisions
m (Relocating version warning) |
No edit summary |
||
(7 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
{{Advanced}} | {{Advanced}} | ||
Macro events are a more advanced feature, allowing [[Library Tokens]] to provide specifically-named macros that will be executed automatically when other actions are taken in MapTool. See the [[:Category:Event|List of Events]] for all supported macro events. | Macro events are a more advanced feature, allowing [[Library Tokens]] to provide specifically-named macros that will be executed automatically when other actions are taken in MapTool. See the [[:Category:Event|List of Events]] for all supported macro events. | ||
== Initiative Events == | == Initiative Events == | ||
There are two initiative events (''introduced in version 1.8'') that are called when an initiative change is occurring. These events '''currently effect only the next/previous initiative operations''' (whether triggered via macro or the Panel), meaning that any mechanism for jumping directly to a specific initiative slot (the `setCurrentInitiative()` function, the `Make Current` panel action, etc.) will bypass these events. This ensures that the GM always has a way of forcing an initiative change without the need to edit any macros. | |||
Both of these events can be present on multiple [[Library Tokens]] (''unlike the otherwise similar [[onTokenMove]]''). All matching handlers will be called, but there is no guarantee on their order. | Both of these events can be present on multiple [[Library Tokens]] (''unlike the otherwise similar [[onTokenMove]]''). All matching handlers will be called, but there is no guarantee on their order. | ||
=== onInitiativeChangeRequest === | === onInitiativeChangeRequest === | ||
The {{code|onInitiativeChangeRequest}} event is called first, and has the opportunity to deny the requested change by setting {{code|init.denyChange}} to {{code|1}}. This is intended for mechanisms that need to ensure certain conditions are met before a turn ends or begins - requiring that all Action Points be expended, that the token be standing on solid ground, etc. All matching handlers will be called, and the change will be rejected if at least one denial is received. Because a change may turn out to be rejected by another handler, authors are advised to avoid any actions with side effects while handling this event. | The {{code|onInitiativeChangeRequest}} event is called first, and has the opportunity to deny the requested change by setting {{code|[[init.denyChange]]}} to {{code|1}}. This is intended for mechanisms that need to ensure certain conditions are met before a turn ends or begins - requiring that all Action Points be expended, that the token be standing on solid ground, etc. All matching handlers will be called, and the change will be rejected if at least one denial is received. Because a change may turn out to be rejected by another handler, authors are advised to avoid any actions with side effects while handling this event. | ||
=== onInitiativeChange === | === onInitiativeChange === | ||
The {{code|onInitiativeChange}} event is called second, and ''only if the change was not denied'' in the first step. This is intended for any turn clean-up or setup steps that should happen as a turn ends or begins - resetting a token's Action Points, updating Token States to highlight the active token, etc. When this event is called the change can no longer be rejected, so these kinds of state-changing actions are appropriate. | The {{code|onInitiativeChange}} event is called second, and ''only if the change was not denied'' in the first step. This is intended for any turn clean-up or setup steps that should happen as a turn ends or begins - resetting a token's Action Points, updating Token States to highlight the active token, etc. When this event is called the change can no longer be rejected, so these kinds of state-changing actions are appropriate. | ||
Line 39: | Line 37: | ||
==== Typical Example ==== | ==== Typical Example ==== | ||
For a typical change, the JSON might look like: | For a typical change, the JSON might look like: | ||
< | <syntaxhighlight lang="javascript"> | ||
{ | { | ||
"old": { | "old": { | ||
Line 57: | Line 55: | ||
"direction": "NEXT" | "direction": "NEXT" | ||
} | } | ||
</ | </syntaxhighlight> | ||
== Examples == | == Examples == | ||
=== Are You Sure? === | === Are You Sure? === | ||
This is a very simple {{code|onInitiativeChangeRequest}} handler that makes the user confirm any attempt to move on from a PC token's turn: | This is a very simple {{code|onInitiativeChangeRequest}} handler that makes the user confirm any attempt to move on from a PC token's turn: | ||
< | <syntaxhighlight lang="mtmacro" line> | ||
[h: "<!-- onInitiativeChangeRequest -->"] | [h: "<!-- onInitiativeChangeRequest -->"] | ||
[h: jsonArgs = macro.args] | [h: jsonArgs = macro.args] | ||
Line 68: | Line 66: | ||
[h, if(isPC(oldToken) && json.get(jsonArgs, "direction") == "NEXT"): | [h, if(isPC(oldToken) && json.get(jsonArgs, "direction") == "NEXT"): | ||
init.denyChange = !input("junk|Are you sure? Click OK to confirm.|ignored|LABEL|SPAN=true")] | init.denyChange = !input("junk|Are you sure? Click OK to confirm.|ignored|LABEL|SPAN=true")] | ||
</ | </syntaxhighlight> | ||
''Note: This is just an example, I will not be held responsible if you inflict this on your players.'' | ''Note: This is just an example, I will not be held responsible if you inflict this on your players.'' | ||
=== Setting States === | === Setting States === | ||
This example automatically updates the "CurrentTurn" state so that the token with initiative is easy to see on the map as well as the Initiative Panel. We only want this to be called if the change is definitely happening, so this is an implementation of {{code|onInitiativeChange}}: | This example automatically updates the "CurrentTurn" state so that the token with initiative is easy to see on the map as well as the Initiative Panel. We only want this to be called if the change is definitely happening, so this is an implementation of {{code|onInitiativeChange}}: | ||
< | <syntaxhighlight lang="mtmacro" line> | ||
[h: "<!-- onInitiativeChange -->"] | [h: "<!-- onInitiativeChange -->"] | ||
[h: jsonArgs = macro.args] | [h: jsonArgs = macro.args] | ||
Line 79: | Line 77: | ||
[h: setState("CurrentTurn", 0, oldToken)] | [h: setState("CurrentTurn", 0, oldToken)] | ||
[h: setState("CurrentTurn", 1, newToken)] | [h: setState("CurrentTurn", 1, newToken)] | ||
</ | </syntaxhighlight> | ||
=== Action Points - A more complete example === | === Action Points - A more complete example === | ||
For this example, let's assume our system uses Action Points. Each turn a token can take a combination of Actions that cost Points, and we reset those Points to their maximum at the start of their next turn. We expect players to use all their Action Points each turn, and want to ask them to confirm any attempt to end their turn before they have used all their AP. | For this example, let's assume our system uses Action Points. Each turn a token can take a combination of Actions that cost Points, and we reset those Points to their maximum at the start of their next turn. We expect players to use all their Action Points each turn, and want to ask them to confirm any attempt to end their turn before they have used all their AP. | ||
First, the {{code|onInitiativeChangeRequest}} handler: | First, the {{code|onInitiativeChangeRequest}} handler: | ||
< | <syntaxhighlight lang="mtmacro" line> | ||
[h: "<!-- onInitiativeChangeRequest -->"] | [h: "<!-- onInitiativeChangeRequest -->"] | ||
[h: jsonArgs = macro.args] | [h: jsonArgs = macro.args] | ||
Line 91: | Line 89: | ||
[h, if(vAP > 0 && json.get(jsonArgs, "direction") == "NEXT"): | [h, if(vAP > 0 && json.get(jsonArgs, "direction") == "NEXT"): | ||
init.denyChange = !input("junk|You still have "+vAP+" AP remaining! Are you sure you want to end your turn?|ignored|LABEL|SPAN=true")] | init.denyChange = !input("junk|You still have "+vAP+" AP remaining! Are you sure you want to end your turn?|ignored|LABEL|SPAN=true")] | ||
</ | </syntaxhighlight> | ||
And the accompanying {{code|onInitiativeChange}} handler to reset the AP: | And the accompanying {{code|onInitiativeChange}} handler to reset the AP: | ||
< | <syntaxhighlight lang="mtmacro" line> | ||
[h: "<!-- onInitiativeChange -->"] | [h: "<!-- onInitiativeChange -->"] | ||
[h: newToken = json.get(json.get(jsonArgs, "new"), "token")] | [h: newToken = json.get(json.get(jsonArgs, "new"), "token")] | ||
[h, if(json.get(jsonArgs, "direction") == "NEXT"): resetProperty("AP", newToken)] | [h, if(json.get(jsonArgs, "direction") == "NEXT"): resetProperty("AP", newToken)] | ||
</ | </syntaxhighlight> | ||
With both of these handlers, we take care to only prompt or update if moving to the {{code|NEXT}} initiative slot - we wouldn't want to reset the AP if we needed to back up to let someone use that 1 remaining point! | With both of these handlers, we take care to only prompt or update if moving to the {{code|NEXT}} initiative slot - we wouldn't want to reset the AP if we needed to back up to let someone use that 1 remaining point! | ||
[[Category:Advanced]] | [[Category:Advanced]] | ||
[[Category:Tutorial]] | [[Category:Tutorial]] |
Latest revision as of 23:59, 14 March 2023
THIS IS AN ADVANCED ARTICLE
Macro events are a more advanced feature, allowing Library Tokens to provide specifically-named macros that will be executed automatically when other actions are taken in MapTool. See the List of Events for all supported macro events.
Initiative Events
There are two initiative events (introduced in version 1.8) that are called when an initiative change is occurring. These events currently effect only the next/previous initiative operations (whether triggered via macro or the Panel), meaning that any mechanism for jumping directly to a specific initiative slot (the `setCurrentInitiative()` function, the `Make Current` panel action, etc.) will bypass these events. This ensures that the GM always has a way of forcing an initiative change without the need to edit any macros.
Both of these events can be present on multiple Library Tokens (unlike the otherwise similar onTokenMove). All matching handlers will be called, but there is no guarantee on their order.
onInitiativeChangeRequest
The onInitiativeChangeRequest
event is called first, and has the opportunity to deny the requested change by setting init.denyChange
to 1
. This is intended for mechanisms that need to ensure certain conditions are met before a turn ends or begins - requiring that all Action Points be expended, that the token be standing on solid ground, etc. All matching handlers will be called, and the change will be rejected if at least one denial is received. Because a change may turn out to be rejected by another handler, authors are advised to avoid any actions with side effects while handling this event.
onInitiativeChange
The onInitiativeChange
event is called second, and only if the change was not denied in the first step. This is intended for any turn clean-up or setup steps that should happen as a turn ends or begins - resetting a token's Action Points, updating Token States to highlight the active token, etc. When this event is called the change can no longer be rejected, so these kinds of state-changing actions are appropriate.
Event JSON details
Handlers of each of these events receive some information about the initiative change in the form of a JSON object macro parameter. This object contains details of the change - specifically the old and new initiative frame, and the direction of the change.
JSON elements | ||
---|---|---|
old / new
|
round
|
round number before / after the pending change |
offset
|
position in the initiative list (starts at 0 , will be -1 if no current initiative)
| |
initiative
|
initiative value of the row described | |
holding
|
1 if the token is On Hold, 0 otherwise
| |
token
|
ID of the corresponding token, or empty string if none | |
direction
|
one of NEXT , PREVIOUS , or ARBITRARY to indicate the direction of change. ARBITRARY is currently unused, as no events are triggered when jumping directly to a specific initiative slot.
|
Typical Example
For a typical change, the JSON might look like:
{
"old": {
"round": 1,
"offset": 3,
"initiative": "14",
"holding": 0,
"token": "7FD82A2533C74DF3B8480F6625AB0EBC"
},
"new": {
"round": 1,
"offset": 4,
"initiative": "12",
"holding": 0,
"token": "FF81F6365AAD4215B7E3758C36C765D1"
},
"direction": "NEXT"
}
Examples
Are You Sure?
This is a very simple onInitiativeChangeRequest
handler that makes the user confirm any attempt to move on from a PC token's turn:
[h: "<!-- onInitiativeChangeRequest -->"]
[h: jsonArgs = macro.args]
[h: oldInfo = json.get(jsonArgs, "old")]
[h: oldToken = json.get(oldInfo, "token")]
[h, if(isPC(oldToken) && json.get(jsonArgs, "direction") == "NEXT"):
init.denyChange = !input("junk|Are you sure? Click OK to confirm.|ignored|LABEL|SPAN=true")]
Note: This is just an example, I will not be held responsible if you inflict this on your players.
Setting States
This example automatically updates the "CurrentTurn" state so that the token with initiative is easy to see on the map as well as the Initiative Panel. We only want this to be called if the change is definitely happening, so this is an implementation of onInitiativeChange
:
[h: "<!-- onInitiativeChange -->"]
[h: jsonArgs = macro.args]
[h: oldToken= json.get(json.get(jsonArgs, "old"), "token")]
[h: newToken = json.get(json.get(jsonArgs, "new"), "token")]
[h: setState("CurrentTurn", 0, oldToken)]
[h: setState("CurrentTurn", 1, newToken)]
Action Points - A more complete example
For this example, let's assume our system uses Action Points. Each turn a token can take a combination of Actions that cost Points, and we reset those Points to their maximum at the start of their next turn. We expect players to use all their Action Points each turn, and want to ask them to confirm any attempt to end their turn before they have used all their AP.
First, the onInitiativeChangeRequest
handler:
[h: "<!-- onInitiativeChangeRequest -->"]
[h: jsonArgs = macro.args]
[h: oldToken= json.get(json.get(jsonArgs, "old"), "token")]
[h: vAP = getProperty("AP", oldToken)]
[h, if(vAP > 0 && json.get(jsonArgs, "direction") == "NEXT"):
init.denyChange = !input("junk|You still have "+vAP+" AP remaining! Are you sure you want to end your turn?|ignored|LABEL|SPAN=true")]
And the accompanying onInitiativeChange
handler to reset the AP:
[h: "<!-- onInitiativeChange -->"]
[h: newToken = json.get(json.get(jsonArgs, "new"), "token")]
[h, if(json.get(jsonArgs, "direction") == "NEXT"): resetProperty("AP", newToken)]
With both of these handlers, we take care to only prompt or update if moving to the NEXT
initiative slot - we wouldn't want to reset the AP if we needed to back up to let someone use that 1 remaining point!