View as Markdown

Teams

Read more about the Teams system in Hiro here.

Core Functions #

SetActivityCalculator #

Specify a function to use when calculating team activity score.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
systems.GetTeamsSystem().SetActivityCalculator(ActivityCalculator)

func ActivityCalculator(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, team *Team) int64 {
  // Used to resolve an activity score for a given team.
  // Implementations may inspect the team members list to use individual activity scores as part of
  // the calculation. Higher activity values should generally be used to indicate more active teams.

  activityScore := 100
	return int64(activityScore)
}

Create #

Create a new team (i.e. Nakama group) with additional metadata which configures the team.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
request := &hiro.TeamCreateRequest{
  Name:          "MyTeam",
  Desc:          "My team description",
  Open:          true,
  Icon:          "iconUrl",
  LangTag:       "",
  SetupMetadata: "<metadata>",
}

team, err := systems.GetTeamsSystem().Create(ctx, logger, nk, request)
if err != nil {
  return err
}

List #

List teams which the user can join.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
request := &hiro.TeamListRequest{
  Cursor:   "",
  Location: "uk",
  Limit:    10,
}

teams, err := systems.GetTeamsSystem().List(ctx, logger, nk, request)
if err != nil {
  return err
}

Search for teams based on given criteria.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
request := &hiro.TeamSearchRequest{
  Input:   "TeamName",
  Limit:   10,
  LangTag: "uk",
}

teams, err := systems.GetTeamsSystem().Search(ctx, db, logger, nk, request)
if err != nil {
  return err
}

Update #

Change one or more properties of the team.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
userId := "userId"
request := &hiro.TeamUpdateRequest{
  Id:   "teamId",
  Name: "MyNewTeamName",
  Open: true,
}

team, err := systems.GetTeamsSystem().Update(ctx, logger, nk, userId, request)
if err != nil {
  return err
}

Get #

Get one or more teams by their identifier.

1
2
3
4
5
6
teamIds := []string{"teamId1", "teamId2"}

teams, err := systems.GetTeamsSystem().Get(ctx, db, logger, nk, teamIds)
if err != nil {
  return err
}

UserTeamsList #

Fetch user accounts and their associated teams.

1
2
3
4
5
6
7
8
request := &hiro.UserTeamsListRequest{
  UserIds: []string{"userId1", "userId2"},
}

list, err := systems.GetTeamsSystem().UserTeamsList(ctx, db, logger, nk, request)
if err != nil {
  return err
}

WriteChatMessage #

Send a message to the user’s team, even when they’re not connected on a realtime socket.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
userId := "userId"
request := &hiro.TeamWriteChatMessageRequest{
  Id:      "teamId",
  Content: "Heya team!",
}

resp, err := systems.GetTeamsSystem().WriteChatMessage(ctx, logger, nk, userId, request)
if err != nil {
  return err
}

UpdateMaxSize #

Set a new maximum team size for the selected team.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

err := systems.GetTeamsSystem().UpdateMaxSize(ctx, logger, db, nk, userId, teamId, 5, true)
if err != nil {
  return err
}

Economy #

StoreList #

Get the defined store items available to the team.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

storeItems, rewardModifiers, timestamp, err := systems.GetTeamsSystem().StoreList(ctx, logger, nk, userId, teamId)
if err != nil {
  return err
}

StorePurchase #

Validate a purchase and give the user ID the appropriate rewards.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
itemId := "itemId"

updatedWallet, updatedInventory, reward, err := systems.GetTeamsSystem().StorePurchase(ctx, logger, db, nk, userId, teamId, itemId)
if err != nil {
  return err
}

SetOnPurchaseReward #

Set a custom reward function which runs after a team store item’s reward is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnPurchaseReward(OnPurchaseReward)

func OnPurchaseReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.TeamEconomyConfigStoreItem, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

WalletGet #

Fetch the wallet for a specified team.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

wallet, err := systems.GetTeamsSystem().WalletGet(ctx, logger, nk, userId, teamId)
if err != nil {
  return err
}

WalletGrant #

Grant currencies to the specified team’s wallet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
userId := "userId"
teamId := "teamId"
currencies := map[string]int64{
  "gold": 100,
}

wallet, err := systems.GetTeamsSystem().WalletGrant(ctx, logger, nk, userId, teamId, currencies)
if err != nil {
  return err
}

Inventory #

InventoryList #

Return the items defined, as well as the computed item sets, for the team by ID.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

items, itemSets, err := systems.GetTeamsSystem().InventoryList(ctx, logger, nk, userId, teamId, "")
if err != nil {
  return err
}

InventoryListInventoryItems #

Return the items which are part of a team’s inventory by ID.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

inventory, err := systems.GetTeamsSystem().InventoryListInventoryItems(ctx, logger, nk, userId, teamId, "")
if err != nil {
  return err
}

InventoryConsumeItems #

Deduct the item(s) from the team’s inventory and run the consume reward for each one, if defined.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
userId := "userId"
teamId := "teamId"
itemIds := map[string]int64{
  "healthPotion": 1,
}

updatedInventory, rewards, instanceRewards, err := systems.GetTeamsSystem().InventoryConsumeItems(ctx, logger, nk, userId, teamId, itemIds, nil, false)
if err != nil {
  return err
}

InventoryGrantItems #

Add the item(s) to a team’s inventory by ID, optionally setting properties on each granted item.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
userId := "userId"
teamId := "teamId"
itemIds := map[string]int64{
  "healthPotion": 1,
}

updatedInventory, newItems, updatedItems, notGrantedItemIds, err := systems.GetTeamsSystem().InventoryGrantItems(ctx, logger, nk, userId, teamId, itemIds, nil, false)
if err != nil {
  return err
}

InventoryUpdateItems #

Update the properties which are stored on each item by instance ID for a team.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
userId := "userId"
teamId := "teamId"
instanceIds := map[string]*hiro.InventoryUpdateItemProperties{
  "instanceId1": {
    StringProperties: map[string]string{"durability": "80"},
  },
}

updatedInventory, err := systems.GetTeamsSystem().InventoryUpdateItems(ctx, logger, nk, userId, teamId, instanceIds)
if err != nil {
  return err
}

SetOnInventoryConsumeReward #

Set a custom reward function which runs after a team inventory item consume reward is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnInventoryConsumeReward(OnInventoryConsumeReward)

func OnInventoryConsumeReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.InventoryConfigItem, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

SetInventoryConfigSource #

Set a custom additional config lookup function for team inventory items.

1
2
3
4
5
6
systems.GetTeamsSystem().SetInventoryConfigSource(InventoryConfigSource)

func InventoryConfigSource(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, configID string) (*hiro.InventoryConfigItem, error) {
  // Look up and return a config item not defined in the static configuration.
  return nil, nil
}

Achievements #

ClaimAchievements #

Claim one or more achievements whose progress has completed by their IDs.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
achievementIds := []string{"achievementId1"}

achievements, repeatAchievements, err := systems.GetTeamsSystem().ClaimAchievements(ctx, logger, nk, userId, teamId, achievementIds, false)
if err != nil {
  return err
}

GetAchievements #

Return all achievements available to the user and their progress on them.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

achievements, repeatAchievements, err := systems.GetTeamsSystem().GetAchievements(ctx, logger, nk, userId, teamId)
if err != nil {
  return err
}

UpdateAchievements #

Update progress on one or more achievements by the same amount.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
userId := "userId"
teamId := "teamId"
achievementUpdates := map[string]int64{
  "achievementId1": 1,
}

achievements, repeatAchievements, err := systems.GetTeamsSystem().UpdateAchievements(ctx, logger, nk, userId, teamId, achievementUpdates)
if err != nil {
  return err
}

ResetAchievements #

Reset one or more achievements by their IDs, deleting their progress from the storage entry.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
achievementIds := []string{"achievementId1"}

achievements, repeatAchievements, err := systems.GetTeamsSystem().ResetAchievements(ctx, logger, nk, userId, teamId, achievementIds)
if err != nil {
  return err
}

SetOnAchievementReward #

Set a custom reward function which runs after an achievement’s reward is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnAchievementReward(OnAchievementReward)

func OnAchievementReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.AchievementsConfigAchievement, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

SetOnSubAchievementReward #

Set a custom reward function which runs after a sub-achievement’s reward is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnSubAchievementReward(OnSubAchievementReward)

func OnSubAchievementReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.AchievementsConfigSubAchievement, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

SetOnAchievementTotalReward #

Set a custom reward function which runs after an achievement’s total reward is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnAchievementTotalReward(OnAchievementTotalReward)

func OnAchievementTotalReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.AchievementsConfigAchievement, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

Event Leaderboards #

ListEventLeaderboard #

Return the available event leaderboards for the team.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

eventLeaderboards, err := systems.GetTeamsSystem().ListEventLeaderboard(ctx, logger, nk, userId, teamId, true, nil)
if err != nil {
  return err
}

GetEventLeaderboard #

Return a specified event leaderboard’s cohort for the team.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
eventLeaderboardId := "eventLeaderboardId"

eventLeaderboard, err := systems.GetTeamsSystem().GetEventLeaderboard(ctx, logger, nk, userId, teamId, eventLeaderboardId)
if err != nil {
  return err
}

RollEventLeaderboard #

Place the team into a new cohort for the specified event leaderboard, if possible.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
eventLeaderboardId := "eventLeaderboardId"

eventLeaderboard, err := systems.GetTeamsSystem().RollEventLeaderboard(ctx, logger, nk, userId, teamId, eventLeaderboardId, nil, false, nil, nil)
if err != nil {
  return err
}

UpdateEventLeaderboard #

Update the team’s score in the specified event leaderboard, and return the team’s updated cohort information.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
eventLeaderboardId := "eventLeaderboardId"

eventLeaderboard, err := systems.GetTeamsSystem().UpdateEventLeaderboard(ctx, logger, db, nk, userId, teamId, eventLeaderboardId, 10, 0, nil, false)
if err != nil {
  return err
}

ClaimEventLeaderboard #

Claim the team’s reward for the given event leaderboard.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
eventLeaderboardId := "eventLeaderboardId"

eventLeaderboard, err := systems.GetTeamsSystem().ClaimEventLeaderboard(ctx, logger, nk, userId, teamId, eventLeaderboardId)
if err != nil {
  return err
}

SetOnEventLeaderboardsReward #

Set a custom reward function which runs after a team event leaderboard’s reward is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnEventLeaderboardsReward(OnEventLeaderboardsReward)

func OnEventLeaderboardsReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.EventLeaderboardsConfigLeaderboard, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

SetOnEventLeaderboardCohortSelection #

Set a custom function that can replace the cohort or opponent selection feature of team event leaderboards.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnEventLeaderboardCohortSelection(OnEventLeaderboardCohortSelection)

func OnEventLeaderboardCohortSelection(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, storageIndex, eventID string, config *hiro.EventLeaderboardsConfigLeaderboard, userID, teamID string, tier int, matchmakerProperties map[string]interface{}) (cohortID string, cohortUserIDs []string, newCohort *hiro.EventLeaderboardCohortConfig, err error) {
  // Select or create the cohort the team is placed into.
  return "", nil, nil, nil
}

DebugFill #

Fill the user’s current cohort with dummy teams for all remaining available slots.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
eventLeaderboardId := "eventLeaderboardId"

eventLeaderboard, err := systems.GetTeamsSystem().DebugFill(ctx, logger, nk, userId, teamId, eventLeaderboardId, 10)
if err != nil {
  return err
}

DebugRandomScores #

Assign random scores to the participants of the team’s current cohort, except to the team itself.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
eventLeaderboardId := "eventLeaderboardId"

eventLeaderboard, err := systems.GetTeamsSystem().DebugRandomScores(ctx, logger, nk, userId, teamId, eventLeaderboardId, 0, 100, 0, 0, nil)
if err != nil {
  return err
}

Leaderboards #

ListLeaderboard #

Return the available team leaderboards.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

leaderboards, err := systems.GetTeamsSystem().ListLeaderboard(ctx, logger, nk, userId, teamId, nil)
if err != nil {
  return err
}

GetLeaderboard #

Return a specified team leaderboard.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
leaderboardId := "leaderboardId"

leaderboard, err := systems.GetTeamsSystem().GetLeaderboard(ctx, logger, nk, userId, teamId, leaderboardId)
if err != nil {
  return err
}

ListLeaderboardScores #

Return a list of team scores for a specified team leaderboard.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
leaderboardId := "leaderboardId"

scoreList, err := systems.GetTeamsSystem().ListLeaderboardScores(ctx, logger, nk, userId, teamId, leaderboardId, "", nil, 10, "", 0)
if err != nil {
  return err
}

ListLeaderboardScoresAroundTeam #

Return a list of team scores for a specified team leaderboard around the caller’s team.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
leaderboardId := "leaderboardId"

scoreList, err := systems.GetTeamsSystem().ListLeaderboardScoresAroundTeam(ctx, logger, nk, userId, teamId, leaderboardId, "", 10, "", 0)
if err != nil {
  return err
}

UpdateLeaderboard #

Submit a team member’s score contribution to the team’s record in the specified team leaderboard.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
leaderboardId := "leaderboardId"

leaderboard, err := systems.GetTeamsSystem().UpdateLeaderboard(ctx, logger, db, nk, userId, teamId, leaderboardId, 10, 0, nil, nil)
if err != nil {
  return err
}

SetOnBeforeUpdateLeaderboardScore #

Set a custom function which runs before a team leaderboard score is updated.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnBeforeUpdateLeaderboardScore(OnBeforeUpdateLeaderboardScore)

func OnBeforeUpdateLeaderboardScore(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, userID, teamID, leaderboardID string, score, subscore int64, metadata map[string]interface{}) (int64, int64, map[string]interface{}, error) {
  // Modify the score, subscore, or metadata before the update is applied.
  return score, subscore, metadata, nil
}

SetOnAfterUpdateLeaderboardScore #

Set a custom function which runs after a team leaderboard score is updated.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnAfterUpdateLeaderboardScore(OnAfterUpdateLeaderboardScore)

func OnAfterUpdateLeaderboardScore(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, userID, teamID, leaderboardID string, score, subscore int64, metadata map[string]interface{}) (int64, int64, map[string]interface{}, error) {
  // React to or adjust the score, subscore, or metadata after the update has been applied.
  return score, subscore, metadata, nil
}

Reward Mailbox #

RewardMailboxList #

List the team reward mailbox, from most recent to oldest.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

mailboxList, err := systems.GetTeamsSystem().RewardMailboxList(ctx, logger, nk, userId, teamId, 10, "")
if err != nil {
  return err
}

RewardMailboxClaim #

Claim a reward and optionally remove it from the team mailbox.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
id := "mailboxEntryId"

mailboxEntry, err := systems.GetTeamsSystem().RewardMailboxClaim(ctx, logger, nk, userId, teamId, id, true)
if err != nil {
  return err
}

RewardMailboxDelete #

Delete a reward from the team mailbox, even if it isn’t yet claimed.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
ids := []string{"mailboxEntryId"}

err := systems.GetTeamsSystem().RewardMailboxDelete(ctx, logger, nk, userId, teamId, ids)
if err != nil {
  return err
}

RewardMailboxGrant #

Grant a reward to the team’s mailbox.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
reward := &hiro.Reward{}

mailboxEntry, err := systems.GetTeamsSystem().RewardMailboxGrant(ctx, logger, nk, userId, teamId, reward)
if err != nil {
  return err
}

SetOnRewardMailboxClaimReward #

Set a custom reward function which runs after a team mailbox reward is rolled during claiming.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnRewardMailboxClaimReward(OnRewardMailboxClaimReward)

func OnRewardMailboxClaimReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.RewardMailboxEntry, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

Stats #

StatsList #

Retrieve the full list of stats for the specified teams.

1
2
3
4
5
6
7
userId := "userId"
teamIds := []string{"teamId1", "teamId2"}

stats, err := systems.GetTeamsSystem().StatsList(ctx, logger, nk, userId, teamIds)
if err != nil {
  return err
}

StatsUpdate #

Update public and private stats for the specified team.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
userId := "userId"
teamId := "teamId"
publicStats := []*hiro.StatUpdate{
  {Name: "wins", Value: 1},
}

statList, err := systems.GetTeamsSystem().StatsUpdate(ctx, logger, nk, userId, teamId, publicStats, nil)
if err != nil {
  return err
}

Gifts #

GiftList #

List available team gifts, including past gifts that still have valid rewards to claim.

1
2
3
4
5
6
7
userId := "userId"
teamId := "teamId"

giftList, err := systems.GetTeamsSystem().GiftList(ctx, logger, nk, userId, teamId)
if err != nil {
  return err
}

GiftContribute #

Update the specified gift with a given contribution amount.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
giftId := "giftId"

ack, err := systems.GetTeamsSystem().GiftContribute(ctx, logger, nk, userId, teamId, giftId, 1)
if err != nil {
  return err
}

GiftClaim #

Claim all pending rewards for a particular gift.

1
2
3
4
5
6
7
8
userId := "userId"
teamId := "teamId"
giftId := "giftId"

ack, err := systems.GetTeamsSystem().GiftClaim(ctx, logger, nk, userId, teamId, giftId, 0)
if err != nil {
  return err
}

SetOnGiftContributeReward #

Set a custom reward function which runs after a team gift contribution reward is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnGiftContributeReward(OnGiftContributeReward)

func OnGiftContributeReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.TeamGift, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}

SetOnGiftContributeCost #

Set a custom reward function which runs after a team gift contribution cost is rolled.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnGiftContributeCost(OnGiftContributeCost)

func OnGiftContributeCost(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.TeamGift, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled cost before it's deducted from the team.
  return reward, nil
}

SetOnGiftClaimReward #

Set a custom reward function which runs after a team gift reward is rolled during claiming.

1
2
3
4
5
6
systems.GetTeamsSystem().SetOnGiftClaimReward(OnGiftClaimReward)

func OnGiftClaimReward(ctx context.Context, logger runtime.Logger, nk runtime.NakamaModule, userID, teamID, sourceID string, source *hiro.TeamGift, rewardConfig *hiro.EconomyConfigReward, reward *hiro.Reward) (*hiro.Reward, error) {
  // Modify or replace the rolled reward before it's granted to the team.
  return reward, nil
}