Mods\IAP Shop Mod

The IAP Shop Mod is used to create and manage in-game shop UI for IAP and currency spending.

Features

Need a feature prioritized or a feature missing from this list? Let @coffee know!

Download the demo maps HERE or play them on the arcade:

landscape

Usage Instructions

Shop Mod 2.0.0 Compatibility

Shop Mod 2.0.0 has some significant changes that break compatibility with earlier versions. Here are the key changes to look out for when upgrading from an earlier version.

Shop Methods

For ease of use, the shop layout (as created by NewShopUI will be referenced as ui.shop throughout this documentation.

The following functions can be used such as:

local shop = require("shop")

local ui = {
  root = DCEI.GetUiRootFrame()
}

-- product definitions
local product_list = {
  {
    product_id = "com.wildsky.example.iap.gold01",
    label = "Handful of Gold",
    display = "shop_gold_lv2",
    price = { usd = 2.99 },
    items = { gold = 1000 }
  },
  {
    product_id = "com.wildsky.example.iap.gold02",
    label = "Barrel of Gold",
    display = "shop_gold_lv4",
    price = { usd = 4.99 },
    items = { gold = 5000 }
  }
}

-- initialize IAP items
shop.InitializeIAP({
  on_purchase_attempt_callback = AttemptAnyItemPurchase,
  on_purchase_success_callback = OnAnyItemPurchase,
  product_list = product_list,
})

-- creates a new shop UI
ui.shop = shop.NewShopUI({ parent = ui.root })

-- initializes a shop with a "Gold" section and gold items
local shop_data = {
  {
    name = "gold",
    display_name = "Gold",
    rows = {
      {
        "com.wildsky.example.iap.gold01",
        "com.wildsky.example.iap.gold02",
      }
    }
  }
}

ui.shop:Initialize(shop_data)

-- show the shop after it's been initialized
ui.shop:Show()

ui.shop:Show()

Shows the in-game shop UI.

ui.shop:Hide()

Hides the in-game shop UI. Note that is automatically called when the close button (ui.shop.CloseButton) on the upper right of the shop UI is pressed.

ui.shop:Initialize( table shop_data )

Initializes the shop layout and generates the shop's sections and starting items. The shop_data parameter should be a list of section_data tables that describe each shop section.

In portrait games, shop sections are created in a vertical list separated by banners. In landscape games, shop sections are created as individual shop tabs. Whether a shop is landscape or portrait is automatically determined by the resolution of the game window.

Example Usage

local shop_data = {
  {
    name = "bundles",
    display_name = "Value Packs",
    navigation = {
      use_display_name = true,
    },
    rows = {
      {
        "com.wildsky.test.iap.bundle.starter01"
      }
    },
    custom = {
      layout = "Portrait/Shop/Section_StarterPack"
    }
  },
  {
    name = "chests",
    display_name = "Chests",
    navigation = {
      use_display_name = true,
    },
    display_timer = {
      label = "Next free chest in:"
    },
    rows = {
      {
        "com.wildsky.test.shop.chest01",
        "com.wildsky.test.shop.chest02"
      }
    }
  },
}

ui.shop:Initialize(shop_data)

table section_data Parameters

ui.shop:AddItemsToSection( string section_name, table items_list, table options )

Dynamically adds items to a shop section. By default, these items will added to the current row for landscape shops and added to a new row for portrait shops.

Items added to the shop in this way can be set to expire at a given time using the expires_at and expires_in options, which will save the expiry time of the item to player save data. An item's expiration time can be cleared with ClearItemTimerData(). Note that item expiry time is tracked with local OS time and NOT with server time, and thus can used without needing to call InitializeServer().

If an item is given an expiry time and its layout contains a frame with the id TimerFrame, it will attempt to hookup and activate the TimerFrame to display the time remaining. If the timer frame has a TimerValueLabel text frame, this text will display the remaining time using FormatTimeDHM() formatting. If the timer frame has a ClockHand frame, it will become animated. The included UI templates Landscape/Template/TimerFrame and Portrait/Template/TimerFrame are for this expressed purpose.

Example Usage

-- adds an item that will expire in 3 days
local day_length_in_seconds = 86400
local options = { expires_in = day_length_in_seconds * 3 }
ui.shop:AddItemsToSection("bundles", { "com.wildsky.test.iap.bundle.starter01" }, options)

Parameters

ui.shop:RemoveItems( table items_list )

Dynamically removes items from the shop. Rows with no items will be removed. Sections with no items will be hidden until they have items again.

Example Usage

local items_list = {
  "com.wildsky.test.iap.bundle.starter01",
  "com.wildsky.test.iap.bundle.starter02",
}
ui.shop:RemoveItems(items_list)

ui.shop:RemoveAllItemsFromSection( string section_name )

Dynamically removes all items from the specified shop section.

Example Usage

ui.shop:RemoveAllItemsFromSection("gold")

ui.shop:RemoveAllItems()

Dynamically removes ALL items from the shop.

Example Usage

ui.shop:RemoveAllItems()

ui.shop:AddTimerUpdateFunction( string timer_id, function update_function )

Adds an update function to the shop's update timer. The shop's update timer is a Real Timer that pauses itself when the shop is hidden and resumes itself when the shop is shown. Any update functions added in this way will be executed each time the shop's update timer ticks, using the global tick rate.

This can be useful for creating your own custom timer displays or otherwise want to constantly update something while the shop is open.

Example Usage

local TIME_SPENT_WITH_SHOP_OPEN = 0
local GLOBAL_TICK_RATE = 0.0625

local timer_id = "shop_time_tracking_timer"
function UpdateShopTimeTracking()
  TIME_SPENT_WITH_SHOP_OPEN = TIME_SPENT_WITH_SHOP_OPEN + GLOBAL_TICK_RATE
end

-- adds a timer that tracks the total time the shop has been open
ui.shop:AddTimerUpdateFunction(timer_id, UpdateShopTimeTracking)

ui.shop:RemoveTimerUpdateFunction( string timer_id )

Removes an existing update function from the shop's update timer.

Example Usage

-- stop tracking the total time the shop has been open
local timer_id = "shop_time_tracking_timer"
ui.shop:RemoveTimerUpdateFunction(timer_id)

For ease of use, the popup layout (as created by NewPopupUI will be referenced as ui.popup throughout this documentation.

The following functions can be used such as:

local shop = require("shop")

local ui = {
  root = DCEI.GetUiRootFrame()
}

-- product definitions
local product_list = {
  {
    product_id = "com.wildsky.example.iap.gold01",
    label = "Handful of Gold",
    display = "shop_gold_lv2",
    price = { usd = 2.99 },
    items = { gold = 1000 }
  },
  {
    product_id = "com.wildsky.example.iap.gold02",
    label = "Barrel of Gold",
    display = "shop_gold_lv4",
    price = { usd = 4.99 },
    items = { gold = 5000 }
  }
}

-- initialize IAP items
shop.InitializeIAP({
  on_purchase_attempt_callback = AttemptAnyItemPurchase,
  on_purchase_success_callback = OnAnyItemPurchase,
  product_list = product_list,
})

-- creates a new popup UI
ui.popup = shop.NewPopupUI()

-- shows a popup with the "Handful of Gold" item
local items_list = { "com.wildsky.example.iap.gold01" }
local options = { display_name = "Deal of the Day" }
ui.popup:Show(items_list, options)

ui.popup:Show( table items_list, table options )

Shows the UI popup with the given items and display options.

Example Usage

local items_list = { "com.wildsky.example.iap.gold01" }
local options = { display_name = "Deal of the Day" }
ui.popup:Show(items_list, options)

Parameters

ui.popup:Update( table items_list )

Removes all existing items in the popup and replaces them with the given items.

Example Usage

local items_list = { "com.wildsky.example.iap.gold02" }
ui.popup:Update(items_list)

Parameters

ui.popup:Hide()

Hides the popup. Note that is automatically called when the close button (ui.popup.CloseButton) on the upper right of the popup UI is pressed.

ui.popup:AddTimerUpdateFunction( string timer_id, function update_function )

Adds an update function to the popup's update timer. Functions the same as the shop update timer, but instead pauses when the popup is hidden.

ui.popup:RemoveTimerUpdateFunction( string timer_id )

Removes an existing update function from the popup's update timer.

Item Methods

These methods can be used on item layouts in the shop or popup UI. Use shop.GetItemLayout() to get an item's shop layout and shop.GetItemLayoutFromPopup() to get an item's popup layout.

item:Remove()

Removes an item, similiar to calling ui.shop.RemoveItems() with a single product id.

Example Usage

local product_id = "com.wildsky.example.iap.gold01"
local item = shop.GetItemLayout(product_id)
item:Remove()

item:ShowPip()

Shows a red pip on the top left of item's layout and the item's section banner. All pips are cleared when the shop is closed.

item:HidePip()

Hide's an item's red pip.

Mod Functions

These are the functions exported by the shop mod. They can be used such as:

local shop = require("shop")

local ui = {
  root = DCEI.GetUiRootFrame()
}

-- creates and shows the shop UI
ui.shop = shop.NewShopUI({ parent = ui.root })

-- initialize IAP data
shop.InitializeIAP({
  on_purchase_attempt_callback = AttemptAnyItemPurchase,
  on_purchase_success_callback = OnAnyItemPurchase,
  product_list = GetProductList(),
  currency_list = CURRENCIES
})

InitializeIAP( table iap_data )

Initializes IAP from IAP data. This requires a product list, functions for purchase attempt and purchase success, and can optionally initialize currencies. This should be called in OnMapStart().

Example Usage

local shop = require("shop")

local ui = {
  root = DCEI.GetUiRootFrame()
}

-- product definitions
local product_list = {
  {
    product_id = "com.wildsky.example.iap.gold01",
    label = "1,000 Gold",
    display = "shop_gold_lv2",
    price = { usd = 2.99 },
    items = { gold = 1000 }
  },
  {
    product_id = "com.wildsky.example.iap.gold02",
    label = "5,000 Gold",
    display = "shop_gold_lv4",
    price = { usd = 4.99 },
    items = { gold = 5000 }
  }
}

-- currency definitions
local currency_list = {
  {
    name = "gold",
    icon = "icon_item_coin"
  }
}

function AttemptAnyItemPurchase(product_id)
  -- if your game has products that can be purchased for in-game currency or by watching ads, you should include the purchase attempt logic for those items here

  if DCEI.Platform == "WindowsPlayer" then
    -- simulate successful purchase when using editor
    -- NOTE: shop.OnAnyItemPurchase() calls the on_purchase_success_callback after updating the item's layout and stock data
    shop.OnAnyItemPurchase(product_id)
  else
    -- otherwise continue standard IAP flow
    -- NOTE: DCEI.PurchaseIapProduct() takes a few seconds to execute and thus acts similarly to a DCEI.Wait() so avoid subsequent code in the same thread
    DCEI.PurchaseIapProduct(product_id)
  end
end

function OnAnyItemPurchase(product_id)
  local item_data = shop.GetProductData(product_id)

  -- deliver purchased items to player
  local items = item_data:GetItemsData()
  if items and items.gold then
    local player_id = 1
    DCEI.AddGold(player_id, items.gold)
  end
end

-- initialize IAP data
shop.InitializeIAP({
  on_purchase_attempt_callback = AttemptAnyItemPurchase,
  on_purchase_success_callback = OnAnyItemPurchase,
  product_list = product_list,
  currency_list = currency_list
})

-- creates a new shop UI
ui.shop = shop.NewShopUI({ parent = ui.root })

-- initializes a shop with a "Gold" section and gold items
local shop_data = {
  {
    name = "gold",
    display_name = "Gold",
    rows = {
      {
        "com.wildsky.example.iap.gold01",
        "com.wildsky.example.iap.gold02",
      }
    }
  }
}

ui.shop:Initialize(shop_data)

-- show the shop after it's been initialized
ui.shop:Show()

table iap_data Parameters

OnAnyItemPurchase( string product_id )

Use this function instead of the on_purchase_success_callback defined in InitializeIAP() when you need to directly call your item purchase function, such as when simulating successful purchase in editor play mode or when successfully purchasing items that cost in-game currency or watching ads.

This function will update the item's layout and stock data before calling the locally defined on_purchase_success_callback.

InitializeServer( table server_data )

Initializes server time tracking from the given data. This is useful for creating items that refresh stock on a daily basis or rotate depending on the day of the week. In server data you can define a callback that occurs whenever server time is fetched or a new day occurs, along with some additional debugging options.

A new server day occurs at 6AM PST. Note that the editor uses your local OS time as it's not connected to the game server.

Once initalized, the shop will attempt to fetch server time whenever any of the following occurs:

  1. When ui.shop:Initialize() is called
  2. When a new server day occurs (at 6AM PST)
  3. The next time the shop is opened IF the previous fetch failed

You can manually call a shop fetch server attempt with AttemptGetServerTime().

table server_data Parameters

Example Usage

function OnShopFetchNewDay()
  -- reset daily ads chest
  local product_id = "com.wildsky.test.shop.chest01"
  local layout = shop.GetItemLayout(product_id)

  shop.ClearItemPurchaseData(product_id)
  layout:Update()

  ui.shop.sections["chests"].timer_display:Reset()
end

-- initialize server data
shop.InitializeServer({
  on_new_server_day_callback = OnShopFetchNewDay 
})

AttemptGetServerTime()

Manually attempts to fetch server time for shop server time tracking using the data given in InitializeServer(). If successful this will call the on_server_time_update_callback. If successful and a new day has occurred since the last server time check, this will call the on_new_server_day_callback.

NewShopUI( transform parent, table options )

Initializes and returns the shop UI layout. If no parent frame is specified by options.parent, the shop will be created in ui.root. By default, whether a shop is landscape or portrait is automatically determined by the resolution of the game window.

The shop UI must be initialized before any shop methods can be used.

Parameters

NewPopupUI( table options )

Initializes and returns the popup UI layout. If no parent frame is specified by options.parent, the shop will be created in ui.root.

The popup UI must be initialized before any popup methods can be used.

Parameters

NewItemInfoUI( table options )

Creates and returns a new item info UI layout. This is the UI that displays when an item's info button is pressed. One is created automatically when the shop is created, but this function can be used to overwrite the existing item info UI under a new parent.

Parameters

ui.shop.info_popup:OnReset()

The Item Info UI has a builtin OnReset() method that gets called when the item info layout is updated with its item data. You can overwrite this function for your own purposes, which is useful for reseting any additional UI added to this UI in its update_func.

GetProductData( string product_id )

Returns an item_data table from its product_id.

GetProductPriceUSD( string product_id )

Returns an item's USD price from its product_id.

GetProductPriceLocalized( string product_id )

Returns an item's localized price from its product_id, if available.

Note that this will only work for published mobile game builds, as it relies on mobile IAP configurations. This will always return nil in editor play mode.

GetProductCustomPriceData( string product_id )

Returns an item's price table from its product_id if the price table contains type and amount values (thus indicating it uses a custom currency).

GetItemLayout( string product_id )

Returns the item's layout from its product_id if the item exists in the Shop UI.

GetItemLayoutFromPopup( string product_id )

Returns the item's layout from its product_id if the item exists in the Popup UI.

GetItemStockAvailable( string product_id )

Returns the number of stock available for an item from its product_id. Stock available is equal to number of times the player has purchased this item subtracted from its stock_limit. Stock available can be reset to its stock limit using ClearItemPurchaseData().

Returns -1 if the item doesn't have a stock limit.

ClearItemPurchaseData( string product_id )

Resets the purchase count of an item from its product_id. Purchase count is only tracked for items that have a stock_limit.

GetTimedOfferData( string product_id )

Returns a table of an item's timed offer data from its product_id. If the item was added to the shop with an expires_at or expires_in option, the returned table will have a key for expires_at with a timestamp of when the item expires.

TimedOfferStillValid( string product_id )

Returns true if the item specified by the product_id has timed offer data and has not expired yet.

Returns true if no timed offer data exists for the item.

ClearItemTimerData( string product_id )

Removes the item specified by the product_id's timer data, preventing such items from expiring.

FormatTimeHM( number seconds )

Returns a formatted string in hours and minutes from the given duration in seconds.

Example Usage

local duration = 4500
local display_time = shop.FormatTimeHM(duration)

local label = DCEI.CreateTextFrame(DCEI.GetUiRootFrame())
DCEI.SetTextFrameText(label, display_time)
-- displays time as 1H 15M

FormatTimeDHM( number seconds )

Returns a formatted string in days, hours, and minutes from the given duration in seconds.

Example Usage

local duration = 240000
local display_time = shop.FormatTimeDHM(duration)

local label = DCEI.CreateTextFrame(DCEI.GetUiRootFrame())
DCEI.SetTextFrameText(label, display_time)
-- displays time as 2D 18H 40M

Purchase Attempt Function

This function is automatically called to initiate an item purchase when a product is selected in the shop UI using either IAP or custom currency.

For IAP items, this function should call DCEI.PurchaseIapProduct(product_id). Note that DCEI.PurchaseIapProduct() will not succeed in the editor so you may want to provide code path for testing (such as in the example below).

For custom currency items, this function should check if the player can afford the item and should subtract the currency amount and call shop.OnAnyItemPurchase() function on success. Be sure to call the mod's shop.OnAnyItemPurchase() function and not the locally declared OnAnyItemPurchase().

Example

function AttemptAnyItemPurchase( product_id )

  DCEI.LogMessage("> Attempt Purchase " .. tostring(product_id))

  local custom_price_data = shop.GetProductCustomPriceData( product_id )
  if custom_price_data then

    -- check conditions for items with custom currency cost
    if custom_price_data.type == "gems" then

      -- for currency gems
      local cost = custom_price_data.amount
      if Player:GetGems() >= cost then
        -- if player can afford purchase, subtract cost and deliver items
        Player:AddGems( -1 * cost )
        shop.OnAnyItemPurchase(product_id)
      else
        -- display feedback for not enough gems
        local text = "Not Enough Gems!"
        DCEI.ShowFeedbackMessage("<color=red>" ..  text)
      end
    end

  else

    -- otherwise attempt standard IAP flow
    if DCEI.Platform == "WindowsPlayer" then
      -- simulate successful purchase when using editor
      shop.OnAnyItemPurchase(product_id)
    else
      -- otherwise continue standard IAP flow
      DCEI.PurchaseIapProduct(product_id)
    end
  end

end

Purchase Success Function

This function is automatically called via shop.OnAnyItemPurchase() when DCEI.PurchaseIapProduct() succeeds. This function should be used to deliver items for IAP or custom currency purchases.

This function is also a good place to log item purchases.

Example

function OnAnyItemPurchase( product_id )

  DCEI.LogMessage("> Successful Purchase " .. tostring(product_id))

  local item_data = shop.GetProductData( product_id )

  -- deliver purchased items to player
  local items = item_data.items
  if items then

    -- deliver gold
    if items.gold then
      Player:AddGold( items.gold )
    end

    -- deliver gems
    if items.gems then
      Player:AddGems( items.gems )
    end

    -- deliver hero shards
    local shards = GetProductShards( items )
    if shards then

      for _, shard in pairs(shards) do
        Player:AddShards( shard.name, shard.count )
      end
    end

    -- roll gacha results and deliver hero shards
    local gacha = GetProductGacha( items )
    if gacha then

      local rolled_shards = ConvertGachaToShards( gacha )
      local shards = GetProductShards( rolled_shards )

      for _, shard in pairs(shards) do
          Player:AddShards( shard.name, shard.count )
      end
    end
  end

  -- log item purchase
  local event_name = "Buy Item"
  local props = {product_id = product_id}

  local price_data = item_data.price
  for k, v in pairs(price_data) do
    props[k] = v
  end

  DCEI.Event.Log(name, props)
end

Item Data

Item data defines each IAP (and custom currency purchase) and allows for customization of the item layout in the shop UI. Item data has 5 required properties.

local item_data = {
  product_id = "com.wildsky.example.iap.gold01",
  label = "Handful of Gold",
  display = "shop_gold_lv2",
  price = { usd = 2.99 },
  items = { gold = 1000 }
}

Properties

string product_id

The product ID of the item. For IAP this must match the item's product ID in the product configuration (such as on Google Play Console or App Store Connect).

The product_id can also be used to reference the item_data or item layout through the various Mod Functions.

table or string label

Determines the label displayed at the top of the item layout (such as "Starter Pack" or "💎 500"). Using a string here will set the name property.

Example
{
  product_id = "com.wildsky.example.shop.gold02",
  label = {
    icon = DCEI.Texture("icon_coin00"),
    item_type = "gold",
    color = "<color=yellow>",
    format_with_commas = true
  },
  display = "shop_gold_lv4",
  items = {
    gold = 10000
  },
  price = {
    type = "gems",
    amount = 500
  }
}

item_label

table or string display

Determines the image display of the item layout. Using a string here will set the image property.

Example
{
  product_id = "com.wildsky.test.iap.bundle.starter02",
  label = "Founder's Pack",
  display = {
    use_item_bundle = true,
    format_with_commas = true
  },
  items = {
    gold = 20000,
    hero_shards_windknight = 8,
    hero_shards_icemage = 8
  },
  price = {
    usd = 9.99
  }
}

item bundle

table price

Determines if the item is purchased as an IAP or with custom currency.

The usd price must be set for IAP using the corresponding value in the product configuration (such as on Google Play Console or App Store Connect). If the product configuration is correct, regional pricing will be displayed. The usd price must still be set for proper revenue logging.

When using custom currency_list, you will have to configure how these are checked in your purchase attempt function.

Note that a product's price data must be retrieved at runtime with item_data:GetPriceData and cannot be retrieved with item_data.price. This is enforced as anti-cheat method as static data is vulnerable to memory hacking on mobile builds.

table items

The list of items (such as gold, gems, chests, etc) delivered to the player on purchase. These items can be used to construct bundle displays by using a registered currency and the display.use_item_bundle option.

You will have to configure how these items are handled in your purchase success function.

Note that a product's items data must be retrieved at runtime with item_data:GetItemsData and cannot be retrieved with item_data.items. This is enforced as anti-cheat method as static data is vulnerable to memory hacking on mobile builds.

(optional) table info

If set, attempts to hookup and show an item's InfoPip and InfoButton frame. When the InfoButton frame is selected, the shop's item info frame will be shown.

Example
local product_list = {
  product_id = "com.wildsky.test.shop.chest01",
  label = {
    name = "Rare Chest",
    color = "<color=#00ffff>",
  },
  display = {
    image = DCEI.Texture("hero_chest_t1"),
    scale = 1.1,
    offset = { y = 4 }
  },
  items = {
    hero_shards_gacha_rare = 8,
  },
  price = {
    type = "gems",
    amount = 250,
  },
  info = {
    update_func = CustomizeStoreItemInfo_Chest,
    label = "Contains 8 [[Rare]] hero shards." 
      .. "\n\n" .. "Drop Rates:"
      .. "\n" .. "[50%] - [[Wind Knight]]"
      .. "\n" .. "[50%] - [[Ice Mage]]"
  },
}

function CustomizeStoreItemInfo_Chest( self )

  -- format text colors
  local text = self.item_data.info.label
  text = text:gsub("%[%[", COLORS.rare)
  text = text:gsub("%]%]", "</color>")
  text = text:gsub("%[", COLORS.yellow)
  text = text:gsub("%]", "</color>")

  DCEI.SetTextFrameText(self.InfoLabel, text)
end

info_a > info_b

(optional) number stock_limit

Used to indicate an item has limited stock. Can be used in conjunction with the display.use_stock_display parameter to show the remaining stock for items using the standard layouts.

Note that items are not automatically removed or disabled when they have 0 stock remaining. You can customize this behavior yourself by checking the item's available stock in its custom update function.

(optional) table custom

Used to customize an item layout. You may find it useful to define your IAP list with a function, rather than a variable declaration when using layout_func to avoid having to juggle declaration ordering.

It's suggested to put any of your own custom item properties (such as subtitles or additional callback functionality) here for organizational purposes.

Methods

These methods can be called with a product's item_data.

Example
local product_id = "com.wildsky.test.shop.chest01"
local item_data = shop.GetProductData(product_id)

-- gets the product's price data
local price_data = item_data:GetPriceData()

item_data:GetPriceData()

Gets a product's price data. This must be retrieved as a function rather than directly as item_data.price as an anti-cheat measure as static data is vulnerable to memory hacking in mobile builds.

item_data:GetItemsData()

Gets a product's items data. This must be retrieved as a function rather than directly as item_data.items as an anti-cheat measure as static data is vulnerable to memory hacking in mobile builds.

item_data:SetPriceData( table price_data )

Sets a product's price data in case you want to dynamically change the price of an item during gameplay. This may be useful for items that are free or an ads reward once per day and then use a normal IAP or in-game currency price.

item_data:SetItemsData( table items_data )

Sets a product's items data in case you want to dynamically change the items contained in a product during gameplay. This may be useful for bundles with rotating item availability without needing to create multiple unique product ids.

Currencies

The currency table is used to associate a currency with an icon for shop display purposes.

Parameters

Example

local CURRENCY_LIST = {
  {
    name = "gold",
    icon = "icon_item_coin",
    priority = 10
  },
  {
    name = "gems",
    icon = "icon_item_gem",
    priority = 9
  },
  {
    name = "hero_shards_windknight",
    icon = "shard_hero_wind_knight",
    bundle_label_format = "{[x]} shards",
    bundle_label_format_single = "{[x]} shard",
  },
  {
    name = "hero_shards_icemage",
    icon = "shard_hero_traveling_mage",
    bundle_label_format = "{[x]} shards",
    bundle_label_format_single = "{[x]} shard",
  },
  {
    name = "hero_shards_tinker",
    icon = "shard_hero_lava_chef",
    bundle_label_format = "{[x]} shards",
    bundle_label_format_single = "{[x]} shard",
  }
}

Customizing Shop UI

Any piece of the shop UI can be customized by forking and overwriting the original layout XML in the UI Editor window. Individual items in the shop can be customized by using the custom layout properties.

customize2

Change Log

2.0.4 (released 3/9/21)

2.0.2 (released 2/18/21)

2.0.0 (released 2/15/21)

1.1.1 (released 9/29/20)

1.1.0 (released 9/16/20)

1.0.0 (released 9/10/20)