# Actions

## Define the Rules of your World

**Actions** are the rules of your **World**. They empower developers to define, validate, and reward player actions within the World. Actions can be used to configure the rules of your World canister (aka your game server) from scratch without having to write a single line of code.

It's an optional framework, giving developers the freedom to use the no-code tool to configure Actions or instead write their own custom World canister code. This flexibility allows game devs to tailor the gaming experience to their vision.

Actions come baked into the [World Template](https://docs.boomdao.xyz/world-canister). Go to the [Game Launcher](https://awcae-maaaa-aaaam-abmyq-cai.icp0.io/) website to deploy a **World Template** and configure **Actions** directly on the website in a few clicks!

***

## How does it work?

Actions are pre-defined rules that players must follow in your game.

***Example: If a player spends 100 Gold they receive 1 Sword***

As you can see, Actions are the backbone of your game economy.

### Action

This is what an Action looks like in code:

```motoko
public type Action = {
    aid : Text;
    name : ?Text;
    description : ?Text;
    imageUrl : ?Text;
    tag : ?Text;
    actionPlugin : ?ActionPlugin;
    actionConstraint : ?ActionConstraint;
    actionResult : ActionResult;
};
```

* **aid:** The action id that identifies this specific action
* **name:** The optional name of this action
* **description:** The optional description of this action
* **imageUrl:** An optional image you want to show related to this action
* **tag:** The optional tag that identifies this action so the client knows how to display it
* **actionPlugin:** An optional plugin that holds custom config data and can run custom logic
* **actionConstraint:** The optional requirements that must be validated before doing this action
* **actionResult:** The result of this action which is made up of many possible outcomes

### ActionPlugin

You can specify an optional plugin with custom config data and custom logic by using an **ActionPlugin.** The World Template comes with default plugins, but you can write your own or import plugins from other projects. Here are the default plugins:

```motoko
public type ActionPlugin = 
{
    #verifyBurnNfts : { canister: Text; requiredNftMetadata : ?[Text]; };
    #verifyTransferIcp : { amt: Float; toPrincipal : Text; };
    #verifyTransferIcrc : {canister: Text; amt: Float; toPrincipal : Text; };
    #claimStakingRewardNft : { canister: Text; requiredAmount : Nat; };
    #claimStakingRewardIcp : { requiredAmount : Float;  };
    #claimStakingRewardIcrc : { canister: Text; requiredAmount : Float; };
};
```

### ActionConstraint

You can specify optional requirements to do an Action by defining **ActionConstraints**:

```motoko
public type ActionConstraint = {
    timeConstraint : ?{
        intervalDuration : Nat;
        actionsPerInterval : Nat;
    };
    entityConstraint : ?[{
        wid : ?TGlobal.worldId;
        gid : TGlobal.groupId;
        eid : TGlobal.entityId;
        fieldName : Text;
        validation : {
            #greaterThanNumber : Float;
            #lessThanNumber : Float;
            #greaterThanEqualToNumber : Float;
            #lessThanEqualToNumber : Float;
            #equalToNumber : Float;
            #equalToString : Text;
            #greaterThanNowTimestamp;
            #lessThanNowTimestamp;
        };
    }];
};
```

* **timeConstraint:** Defines how many times the player can do the action in a certain time interval.&#x20;

  *eg. Collect gems 4 times every 24 hours. Or 1 time every 6 hours. etc.*
* **entityConstraint:** Defines a list of Entity requirements the player must have in order to do the action. An Entity constraint can even check Entities in another World!&#x20;

  *eg. Have greater than 100 Gold in Plethora to buy a Sword in Cubetopia. Or have a Luck buff that isn't expired to do a lucky dice roll. Or have a Stat with attribute that equals "Race Master" to play a secret racing map.*

### ActionResult

You can specify the resulting outcomes of an Action by defining the **ActionResult.** An **ActionResult** has a list of **ActionOutcomes.** Each **ActionOutcome** has a list of possibleOutcomes, meaning you can specify the likelihood of each possible **ActionOutcomeOption** being chosen as the **ActionOutcome**:

```motoko
public type ActionResult = {
    outcomes: [ActionOutcome];
};

public type ActionOutcome = {
    possibleOutcomes: [ActionOutcomeOption];
};

public type ActionOutcomeOption = {
    weight : Float;
    option : {
        #mintToken : MintToken;
        #mintNft : MintNft;
        #deleteEntity : DeleteEntity;
        #renewTimestamp : RenewTimestamp;
        #setString : SetString;
        #setNumber : SetNumber;
        #decrementNumber : DecrementNumber;
        #incrementNumber : IncrementNumber;
    };
};
```

#### What is weight?

You'll notice each **ActionOutcomeOption** has a **weight** field. The **weight** field for each potential outcome determines its probability of being chosen. A higher weight means a higher chance of manifesting that outcome.&#x20;

For example, if there are two outcomes, one with a weight of 1 and the other with a weight of 9, the latter is nine times more likely to occur, as the weights reflect their proportions in the total pool of outcomes.

If there is only one ActionOutcomeOption in the list of possibleOutcomes, it will have a 100% chance of occurring.

***

## Using Actions to Mint NFTs and ICRC tokens

You'll notice there are fields called **MintToken** and **MintNft** in the **ActionOutcomeOption**. These enable you to set a probability of Tokens or NFTs being minted as an outcome. The **World** canister does the minting by calling the NFT canister.&#x20;

Your **World** canister must be an admin of your NFT or ICRC canister in order to handle the minting, you can easily create NFT or ICRC collections and add admins using the [Game Launcher](https://awcae-maaaa-aaaam-abmyq-cai.icp0.io/) website.

Here's what the **MintToken** and **MintNft** fields look like:

```motoko
public type MintToken = 
{
    quantity : Float;
    canister : Text;
};
public type MintNft = 
{
    index : ? Nat32;
    canister : Text;
    assetId: Text;
    metadata: Text;
};
```

## Integration with Unity

The process of integrating the Action System with your Unity game is simple. When a player wants to do an Action, call this function in your **World** canister:&#x20;

```motoko
processAction(actionArg: ActionArg)
```

You'll notice it takes an **ActionArg** parameter that gives the **World** more context about the Action the player wants to call. Here are examples of **ActionArgs**:

```motoko
public type ActionArg = 
{
    #default : {actionId: Text; };
    #verifyBurnNfts : {actionId: Text; indexes: [Nat32]; };
    #verifyTransferIcp : {actionId: Text; blockIndex: Nat64; };
    #verifyTransferIcrc : {actionId: Text; blockIndex: Nat; };
    #claimStakingRewardNft : {actionId: Text; };
    #claimStakingRewardIcp : {actionId: Text; };
    #claimStakingRewardIcrc : {actionId: Text; };
};
```

The **World** canister will then lookup the **ActionConfig** using the **actionId** that is passed in **ActionArg**, and check for any custom **ActionPlugins** like verifying the ICP ledger or verifying an NFT was burned.&#x20;

Then the **World** will call the **processAction()** function in **UserNode**:

```motoko
processAction(uid : Text, aid : Text, actionConstraint : ?ActionConstraint, outcomes : [ActionOutcomeOption])
```

This function in **UserNode** will handle validating the **ActionConstraint**, processing the **ActionResult** outcomes, and apply those outcomes to their respective **Entities**.&#x20;

**processAction()** will return the result as an array of Entities that were affected:

```motoko
( [Entity], Text )
```

Then the **World** canister will read the tuple and handle minting any Tokens and NFTs if necessary.&#x20;

***

## Watch the Tutorial Video

Learn how to configure Actions in your World canister from the Game Launcher

{% embed url="<https://youtu.be/ANVfouAAO_Q?si=fLQRu6XChWbxRzbc&t=469>" %}
