This is a documentation for Board Game Arena: play board games online !
Diferenzas entre revisións de «SandboxScripts»
Een (conversa | contribucións) |
|||
(Non se amosan 31 revisións do historial feitas por 2 usuarios.) | |||
Liña 40: | Liña 40: | ||
* You don't have to save&publish from the Sandbox editor for each modification of your script : each time you save your script (control+S), the script used for all test sessions is updated. Note that the production version on BGA is of course NOT updated until you explicitly save&publish again your project. | * You don't have to save&publish from the Sandbox editor for each modification of your script : each time you save your script (control+S), the script used for all test sessions is updated. Note that the production version on BGA is of course NOT updated until you explicitly save&publish again your project. | ||
* To inspect the content of a variable, you can use bga.log() in combination with JSON.stringify(). For example : | |||
bga.log( JSON.stringify( bga.getPlayers()) ); | |||
* Alternatively to bga.log(), you can use bga.exit( "my message" ) to debug your script. With bga.exit, the script execution immediately stops and all previous game changes are cancelled, so this is very practical to try and retry an action until your script is fine. | * Alternatively to bga.log(), you can use bga.exit( "my message" ) to debug your script. With bga.exit, the script execution immediately stops and all previous game changes are cancelled, so this is very practical to try and retry an action until your script is fine. | ||
Liña 45: | Liña 49: | ||
* We advise you to develop first a full playable version of the game without the scripts, and THEN to script it. | * We advise you to develop first a full playable version of the game without the scripts, and THEN to script it. | ||
* | * On Board Game Arena, players have come to expect fully implemented games with all rules enforced. So even if it's technically possible not to script the full game and to implement the game only partially, in most cases we'll publish only fully scripted games :) | ||
== Examples/Tutorials == | |||
In addition to the projects you will create, you have readonly access in the sandbox to two example projects: "linesofaction" is an abstract and "apocalypseazcc" is a card game. | |||
These two projects are fully scripted, so you can check out the scripts and use them as examples/tutorials. | |||
= Functions you can use in your Sandbox scripts= | = Functions you can use in your Sandbox scripts= | ||
Liña 138: | Liña 148: | ||
=== bga.speechBubble( target, text, (optional) args, (optional) delay, (optional) duration, (optional) size ) === | === bga.speechBubble( target, text, (optional) args, (optional) delay, (optional) duration, (optional) size ) === | ||
Display a " | Display a "speech bubble", attached to the specified target, containing the specified text. | ||
You can use "args" to customize text exactly like with bga.log. | You can use "args" to customize text exactly like with bga.log. | ||
Liña 149: | Liña 159: | ||
bga.speechBubble( _("I play ${nbr} cards"), { nbr : 4 }, 0 ); | bga.speechBubble( _("I play ${nbr} cards"), { nbr : 4 }, 0 ); | ||
bga.speechBubble( _("Good for you!"), { }, 2000 ); | bga.speechBubble( _("Good for you!"), { }, 2000 ); | ||
=== bga.displayScoring( target, color, score ) === | |||
Display an animated temporary "score number", attached to the specified target. | |||
"color" should be the color of the player who is scoring for that target. | |||
== Get / search game elements and their properties == | == Get / search game elements and their properties == | ||
== bga.getElement( selector, ( | === bga.getElement( selector, (optional) fields ) === | ||
Allow you to retrieve informations about one game element specified using "selector" argument. | Allow you to retrieve informations about one game element specified using "selector" argument. | ||
Liña 193: | Liña 209: | ||
// Note the use of "limit:1" which allows us to retrieve only 1 element. | // Note the use of "limit:1" which allows us to retrieve only 1 element. | ||
var first_card_on_deck_id = bga.getElement( { parent: 1234, limit:1 } ); | var first_card_on_deck_id = bga.getElement( { parent: 1234, limit:1 } ); | ||
// | |||
// You can also get nested properties such as the ids of the child elements of one element, or a custom property placed on the parent element | |||
var totem_places = bga.getElements( {tag:'TOTEMZONE'}, ['id','childs:id','childs:tags','parent:id','parent:c_value'] ); | |||
=== bga.getElements( selector, (optional) fields ) === | |||
Returns an object holding the properties of the elements matching the selector. | |||
// Basic example: unselect all selected elements | |||
bga.removeStyle( bga.getElements( {tag: 'sbstyle_selected'}), 'selected' ); | |||
=== bga.getElementsArray( selector, (optional) fields ) === | |||
Returns an array of all elements matching the selector, holding the required properties. | |||
// Basic example: get id of selected element | |||
var selected_tokens = bga.getElementsArray( {tag: 'sbstyle_selected' } ); | |||
var token_id = null; | |||
if (selected_tokens.length > 0) { | |||
token_id = selected_tokens[0]; | |||
} | |||
return token_id; | |||
// Classic example: get array of elements and iterate over it | |||
var all_cells = bga.getElementsArray( {tag: 'CELL'}, ['id','name','tags'] ); | |||
for (var i=0; i<all_cells.length; i++) { | |||
// ... process each cell ... | |||
} | |||
== Utility methods == | |||
=== bga.isOn( element_id, parent_id ) === | |||
Return true if "element_id" is a descendant of "parent_id" (ie : if element_id game element has been placed on parent_id game element). | |||
// Example : | |||
if( bga.isOn( bga.getElementIfByName( 'Turn counter' ), bga.getElementIfByName( 'Turn 6' ) ) | |||
{ | |||
// Trigger game end | |||
} | |||
== Trigger most common game actions == | |||
=== moveTo( id, target, path ) === | |||
Move element to specified target id (eventually following path defined by an array of element ids to pass over on the way) | |||
The exact destination of element depends on target's "howToArrange" property ("How elements are arranged on it?" : spreaded/deck/...). | |||
// Example : | |||
bga.moveTo( bga.getElementIdByName( 'Turn counter' ), bga.getElementIdByName( 'Turn 3' ) ); | |||
=== removeElement( id ) === | |||
Deletes all properties from this element and remove it from play. Warning: it won't be recoverable! If you may need it later, you should move it inside a zone with visibility set to "Everyone, but hide what's inside" instead of removing it. | |||
=== flip( element_ids ) === | |||
Flip target element (or array of elements) if the elements are flippable (ex: cards). | |||
=== shuffle( element_ids ) === | |||
Shuffle elements contained inside the target element (or array of elements). | |||
=== roll( element_ids ) === | |||
Roll the target element (or array of elements). Target elements must have the property "Can be rolled" set. | |||
=== setDie( element_ids, value ) === | |||
Set the target element (or array of elements) with this value. Target elements must have the property "Can set value" set. | |||
=== deal( deck_id, target_tag, nbr_per_target ) === | |||
Deal nbr_per_target cards from deck_id element to all elements having target_tag. | |||
=== incScore( color, value ) === | |||
Increases the score for the player with the specified color, of the specified increment value. | |||
=== | === setScore( color, value ) === | ||
Sets the score for the player with the specified color. | |||
=== getScore( color ) === | |||
Gets the score of the player with the specified color. | |||
== | == Gamestate functions == | ||
You can define your game flow with a list of states by adding a "states" function to your script. | |||
function states() | |||
{ | { | ||
return { | |||
// Init game | |||
100: { | |||
onState: 'postSetup', | |||
transitions: { done:200 } | |||
}, | |||
200: { | |||
description: _('${actplayer} must move a piece'), | |||
descriptionmyturn: _('${you} must move a piece'), | |||
possibleactions: ['movePiece'], | |||
transitions: { nextPlayer: 200 } | |||
}, | |||
}; | |||
} | } | ||
== | Then, you will be able to use the following functions to manage the game flow. | ||
=== checkAction( action ) === | |||
Check if action is valid regarding current game state and raise an error if it's not the case. | |||
=== isActionPossible( action ) === | |||
Check if action is valid regarding current game state and returns a boolean with the appropriate value. | |||
=== getActivePlayerColor() === | |||
Returns the color code of the currently active player | |||
=== getActivePlayerName() === | |||
Returns the color code of the currently active player | |||
=== nextPlayer() === | |||
Activates the next player in play order. | |||
=== activeAllPlayers() === | |||
Activates all players (multiactive state). | |||
=== endTurn( transition ) === | |||
Make the current player inactive and go to the next state matching the provided transition if all players are inactive (multiactive state) | |||
=== getActivePlayerColors() === | |||
Returns the colors code of the currently active players | |||
=== getCurrentPlayerColor() === | |||
Returns the color code of the current player (the player who made the interface action being handled; may not be the active player). | |||
=== nextState( transition ) === | |||
Moves to the next state matching the provided transition. | |||
=== gotoState( state_id ) === | |||
Jumps to specified state. | |||
=== getPlayers() === | |||
Returns an array of players with the players information. | |||
=== setGameProgression( progression ) === | |||
Updates the game progression percentage (progression must be an integer between 0 and 100) | |||
=== endGame() === | |||
When the end game condition is met, you can use this function to end the game (after setting the appropriate scores!) | |||
== Other functions == | == Other functions == | ||
Liña 280: | Liña 392: | ||
Tips : if you want to execute several consecutive "moveTo", you should "bga.pause" between them, otherwise your element will move directly to the final destination. | Tips : if you want to execute several consecutive "moveTo", you should "bga.pause" between them, otherwise your element will move directly to the final destination. | ||
=== stopEvent() === | |||
Must be used to stop the event propagation if you have two clickable elements on top of one another and you want only the onclick function matching the one on top to be triggered. | |||
function onClickCard( card_id, selection_ids ) { | |||
// Cancel event propagation | |||
bga.stopEvent(); | |||
[... manage the event ...] | |||
} | |||
=== hasTag( id, tag ) === | |||
Returns true if the element with this id has this tag. | |||
=== addTag( id, tag ) === | |||
Adds this tag to the element with this id. | |||
=== removeTag( id, tag ) === | |||
Removes this tag from the element with this id. | |||
=== addStyle( id, style ) === | |||
Adds this style to the element with this id. | |||
Predefined styles are: SELECTED / LIGHT / LIGHTBACKGROUND / REDSELECTED / CLICKABLE / ROUNDED / CLICKABLE_ROUNDED | |||
=== removeStyle( id, style ) === | |||
Removes this style from the element with this id. | |||
=== setProperties( props ) === | |||
This function allows to directly update properties of an object, and to manage custom properties if needed (custom properties must start with prefix "c_"). | |||
Example: | |||
// Update player labels for player zones from "<color> player" to actual player name | |||
var players = bga.getPlayers(); | |||
for (var color in players) { | |||
player = players[color]; | |||
var labelId = null; | |||
if (color == 'ff0000') labelId = bga.getElement( {name: 'Red player'} ); | |||
if (color == '008000') labelId = bga.getElement( {name: 'Green player'} ); | |||
if (color == '0000ff') labelId = bga.getElement( {name: 'Blue player'} ); | |||
if (color == 'ffa500') labelId = bga.getElement( {name: 'Yellow player'} ); | |||
var props = []; | |||
props[labelId] = {name: player.name}; | |||
bga.setProperties( props ); | |||
} |
Revisión actual feita o 25 de maio de 2018 ás 10:03
This is the reference of functions you can call from your Sandbox scripts.
Javascript
BGA Sandbox scripts are written in Javascript.
Using Javascript, you can write scripts to automate moves for your Sandbox games & provide rules reinforcement.
Important : in the opposite of the most common usage of Javascript, Sandbox scripts are executed on server side.
BGA API
To interact with your BGA Sandbox game, we provide you an API.
With this API, you can get properties values of game elements from the current game situation, modify them and/or trigger the game actions (ex : move this element here, flip this card, and so on).
Quick start
Hello World Script
From Sandbox editor "interface view" tab, select an element, and access to its property (top right icon).
Go to "Scripts (advanced)" section.
In front of "When this element is clicked", enter "onMyClick".
Close the window. Go to "script view" tab.
Enter the following :
function onMyClick( element_id ) { bga.log("Hello world! You just clicked on element " + element_id + ". Congrats!"); }
Save & publish your project, starts a test session, click on the previous element : your message appears in the log on the right!
Top useful tips
- You don't have to save&publish from the Sandbox editor for each modification of your script : each time you save your script (control+S), the script used for all test sessions is updated. Note that the production version on BGA is of course NOT updated until you explicitly save&publish again your project.
- To inspect the content of a variable, you can use bga.log() in combination with JSON.stringify(). For example :
bga.log( JSON.stringify( bga.getPlayers()) );
- Alternatively to bga.log(), you can use bga.exit( "my message" ) to debug your script. With bga.exit, the script execution immediately stops and all previous game changes are cancelled, so this is very practical to try and retry an action until your script is fine.
- We advise you to develop first a full playable version of the game without the scripts, and THEN to script it.
- On Board Game Arena, players have come to expect fully implemented games with all rules enforced. So even if it's technically possible not to script the full game and to implement the game only partially, in most cases we'll publish only fully scripted games :)
Examples/Tutorials
In addition to the projects you will create, you have readonly access in the sandbox to two example projects: "linesofaction" is an abstract and "apocalypseazcc" is a card game.
These two projects are fully scripted, so you can check out the scripts and use them as examples/tutorials.
Functions you can use in your Sandbox scripts
Debugging functions
bga.trace( txt / obj )
Write something immediately in the BGA log (on the right of the screen).
This is the most practical way to debug your script :)
Important : bga.trace is for debugging purpose only and won't be displayed on production.
Note : you can also pass an object in parameter. This will dump the content of this object in the log.
Note : in the opposite of bga.log, bga.trace is NOT cancelled if the game action failed (after a call to bga.cancel or bga.error). This makes bga.trace very practical to debug a game action that failed, and for this reason you should probably NEVER use bga.log for debugging purpose.
// Example : write "Hello world" in the log bga.trace( "Hello world" );
// Example : dump an associative array in the log bga.trace( { mykey: 'myvalue', another_key: 'another_value' } );
bga.exit( txt / obj )
Stop the script immediately, display the "txt" messages and cancel (ie : rollback) on every previous API call except bga.trace :
ALL previous BGA api call are canceled and there will be no visible changes on the interface (ex : no moves, no visible property changes, ...). Only "bga.trace" API commands are kept so you can debug.
bga.exit is very practical when you want to repeat a game action again and again to debug it : with a call to bga.exit at the end of your script, you make sure that your game situation will be kept unchanged after each test.
// Example : bga.exit( "My script is stopped by this call" );
// Example with dumping a javascript variable bga.exit( my_variable_to_dump );
Cancelling a game action
bga.cancel( txt )
This is the function to use when a player is doing something against game rules.
The text message in parameter will be displayed to this player as a "red message", so he/she can understand the rule.
All previous BGA api call are cancelled, and there will be no visible changes on the interface.
// Example : bga.cancel( _("You cannot move this piece here") );
Note : most of the time, you should wrap your text inside a _() translation marker to make this string translatable.
bga.error( text )
This is the function to use when some unexpected error happens in your script.
The text message will be displayed to user, with mention "Unexpected error". The player will be incited to fill a bug report. The purpose of the message is to help you to identify the bug.
All previous BGA api call are cancelled, and there will be no visible changes on the interface.
// Example : if( card_picked === null ) { bga.error( "Cannot find a card to pick !" ); }
Note : you should NEVER wrap text inside bga.error with _() translation marker, because unexpected error should not be translate (so you can eventually recognize them when reported by players in bug report).
Game log (history)
bga.log( txt, (optional) args )
Write something in the BGA log on the right.
// Example : simple log bga.log( _("A new round starts") );
You may add arguments to your log, like this :
// Example: log with argument to display a card name. // In this example, variable "event_name" is specified afterwards. // Note that using this, game translators only have to translate one "Event XXX is triggered" string for all possible events. bga.log( _("Event ${event_name} is triggered"), { event_name: _( "Armageddon" ) } ) );
Note that argument "player_name" is ALWAYS pre-set with the name of the current player, so you can use it immediately.
// Example : bga.log( _("${player_name} draw a card from the deck") );
bga.speechBubble( target, text, (optional) args, (optional) delay, (optional) duration, (optional) size )
Display a "speech bubble", attached to the specified target, containing the specified text.
You can use "args" to customize text exactly like with bga.log.
delay : milliseconds to wait before displaying the speech bubble (default : 0). duration : how long to show the speech bubble in milliseconds (default : 3000). size : size of the text in percent (default: 100)
// Example : bga.speechBubble( _("I play ${nbr} cards"), { nbr : 4 }, 0 ); bga.speechBubble( _("Good for you!"), { }, 2000 );
bga.displayScoring( target, color, score )
Display an animated temporary "score number", attached to the specified target.
"color" should be the color of the player who is scoring for that target.
Get / search game elements and their properties
bga.getElement( selector, (optional) fields )
Allow you to retrieve informations about one game element specified using "selector" argument.
Return null if no element is found.
Note : getElement throw an error if several elements matches the selector. If you want to retrieve several elements, you should use "getElements" instead of "getElement".
The following examples are showing all the possible use of bga.getElement :
// Basic example : // Retrieve the ID of a game element using its name ("Deck") var deck_id = bga.getElement( { name: "Deck" } ); // Return : 1234
// Examples using "field" parameter : // Retrieve a specific property from a game element using its name ("Deck") var deck_id = bga.getElement( { name: "Deck" }, 'x' ); // Return : 20 // Retrieve several properties from the previous element var deck_properties = bga.getElement( { name: "Deck" }, ['name','id','parent', 'x','y','canShuffle'] ); // Return : { name:'Deck', id:1234, parent:4321, x: 20, y:50, canShuffle: true } // Note : as you can see, getElement returns: // _ the element ID by default, or // _ a single value if you request a single field, or // _ an object if you request several fields
// Examples using different "selector" paramter // Retrieve an element name from its id var deck_name = bga.getElement( { id: 1234 }, ['name'] ); // Return : "Deck"
// Retrieve the last child element of another element // Here, we are requesting for elements who has element with ID=1234 (Deck) as their parent // Note the use of "limit:1" which allows us to retrieve only 1 element. var first_card_on_deck_id = bga.getElement( { parent: 1234, limit:1 } ); // You can also get nested properties such as the ids of the child elements of one element, or a custom property placed on the parent element var totem_places = bga.getElements( {tag:'TOTEMZONE'}, ['id','childs:id','childs:tags','parent:id','parent:c_value'] );
bga.getElements( selector, (optional) fields )
Returns an object holding the properties of the elements matching the selector.
// Basic example: unselect all selected elements bga.removeStyle( bga.getElements( {tag: 'sbstyle_selected'}), 'selected' );
bga.getElementsArray( selector, (optional) fields )
Returns an array of all elements matching the selector, holding the required properties.
// Basic example: get id of selected element var selected_tokens = bga.getElementsArray( {tag: 'sbstyle_selected' } ); var token_id = null; if (selected_tokens.length > 0) { token_id = selected_tokens[0]; } return token_id;
// Classic example: get array of elements and iterate over it var all_cells = bga.getElementsArray( {tag: 'CELL'}, ['id','name','tags'] ); for (var i=0; i<all_cells.length; i++) { // ... process each cell ... }
Utility methods
bga.isOn( element_id, parent_id )
Return true if "element_id" is a descendant of "parent_id" (ie : if element_id game element has been placed on parent_id game element).
// Example : if( bga.isOn( bga.getElementIfByName( 'Turn counter' ), bga.getElementIfByName( 'Turn 6' ) ) { // Trigger game end }
Trigger most common game actions
moveTo( id, target, path )
Move element to specified target id (eventually following path defined by an array of element ids to pass over on the way)
The exact destination of element depends on target's "howToArrange" property ("How elements are arranged on it?" : spreaded/deck/...).
// Example : bga.moveTo( bga.getElementIdByName( 'Turn counter' ), bga.getElementIdByName( 'Turn 3' ) );
removeElement( id )
Deletes all properties from this element and remove it from play. Warning: it won't be recoverable! If you may need it later, you should move it inside a zone with visibility set to "Everyone, but hide what's inside" instead of removing it.
flip( element_ids )
Flip target element (or array of elements) if the elements are flippable (ex: cards).
shuffle( element_ids )
Shuffle elements contained inside the target element (or array of elements).
roll( element_ids )
Roll the target element (or array of elements). Target elements must have the property "Can be rolled" set.
setDie( element_ids, value )
Set the target element (or array of elements) with this value. Target elements must have the property "Can set value" set.
deal( deck_id, target_tag, nbr_per_target )
Deal nbr_per_target cards from deck_id element to all elements having target_tag.
incScore( color, value )
Increases the score for the player with the specified color, of the specified increment value.
setScore( color, value )
Sets the score for the player with the specified color.
getScore( color )
Gets the score of the player with the specified color.
Gamestate functions
You can define your game flow with a list of states by adding a "states" function to your script.
function states() { return { // Init game 100: { onState: 'postSetup', transitions: { done:200 } }, 200: { description: _('${actplayer} must move a piece'), descriptionmyturn: _('${you} must move a piece'), possibleactions: ['movePiece'], transitions: { nextPlayer: 200 } }, }; }
Then, you will be able to use the following functions to manage the game flow.
checkAction( action )
Check if action is valid regarding current game state and raise an error if it's not the case.
isActionPossible( action )
Check if action is valid regarding current game state and returns a boolean with the appropriate value.
getActivePlayerColor()
Returns the color code of the currently active player
getActivePlayerName()
Returns the color code of the currently active player
nextPlayer()
Activates the next player in play order.
activeAllPlayers()
Activates all players (multiactive state).
endTurn( transition )
Make the current player inactive and go to the next state matching the provided transition if all players are inactive (multiactive state)
getActivePlayerColors()
Returns the colors code of the currently active players
getCurrentPlayerColor()
Returns the color code of the current player (the player who made the interface action being handled; may not be the active player).
nextState( transition )
Moves to the next state matching the provided transition.
gotoState( state_id )
Jumps to specified state.
getPlayers()
Returns an array of players with the players information.
setGameProgression( progression )
Updates the game progression percentage (progression must be an integer between 0 and 100)
endGame()
When the end game condition is met, you can use this function to end the game (after setting the appropriate scores!)
Other functions
pause( milliseconds )
Pause the client interface during a specified number of milliseconds.
If you do not use bga.pause, all Sandbox game actions are executed immediately and synchronously.
// Example : bga.log( "1" ); // Will be displayed immediately on the log bga.pause( 3000 ); // pause during 3 seconds bga.log( "2" ); // Will be displayed after the 3 second on the log bga.log( "3" ); // Will be displayed right after the previous one, without delay.
Tips : if you want to execute several consecutive "moveTo", you should "bga.pause" between them, otherwise your element will move directly to the final destination.
stopEvent()
Must be used to stop the event propagation if you have two clickable elements on top of one another and you want only the onclick function matching the one on top to be triggered.
function onClickCard( card_id, selection_ids ) { // Cancel event propagation bga.stopEvent(); [... manage the event ...] }
hasTag( id, tag )
Returns true if the element with this id has this tag.
addTag( id, tag )
Adds this tag to the element with this id.
removeTag( id, tag )
Removes this tag from the element with this id.
addStyle( id, style )
Adds this style to the element with this id.
Predefined styles are: SELECTED / LIGHT / LIGHTBACKGROUND / REDSELECTED / CLICKABLE / ROUNDED / CLICKABLE_ROUNDED
removeStyle( id, style )
Removes this style from the element with this id.
setProperties( props )
This function allows to directly update properties of an object, and to manage custom properties if needed (custom properties must start with prefix "c_").
Example:
// Update player labels for player zones from "<color> player" to actual player name var players = bga.getPlayers(); for (var color in players) { player = players[color]; var labelId = null; if (color == 'ff0000') labelId = bga.getElement( {name: 'Red player'} ); if (color == '008000') labelId = bga.getElement( {name: 'Green player'} ); if (color == '0000ff') labelId = bga.getElement( {name: 'Blue player'} ); if (color == 'ffa500') labelId = bga.getElement( {name: 'Yellow player'} ); var props = []; props[labelId] = {name: player.name}; bga.setProperties( props ); }