Skip to content

Commit

Permalink
Sfinv: Add sfinv to allow tabs to be added to the inventory
Browse files Browse the repository at this point in the history
rubenwardy authored and paramat committed Nov 27, 2016
1 parent e837621 commit d42ae71
Showing 8 changed files with 483 additions and 234 deletions.
106 changes: 105 additions & 1 deletion game_api.txt
Original file line number Diff line number Diff line change
@@ -70,7 +70,17 @@ Beds API
Creative API
------------

A global string called `creative.formspec_add` was added which allows mods to add additional formspec elements onto the default creative inventory formspec to be drawn after each update.
Use `creative.register_tab(name, title, items)` to add a tab with filtered items.
For example,

creative.register_tab("tools", "Tools", minetest.registered_tools)

is used to show all tools. Name is used in the sfinv page name, title is the
human readable title.

The contents of `creative.formspec_add` is appended to every creative inventory
page. Mods can use it to add additional formspec elements onto the default
creative inventory formspec to be drawn after each update.

Doors API
---------
@@ -391,6 +401,100 @@ set a players home position and teleport a player to home position.
* return value: false if player cannot be sent home, otherwise true


Sfinv API
---------

### sfinv Methods

* sfinv.set_player_inventory_formspec(player, context) - builds page formspec
and calls set_inventory_formspec().
If context is nil, it is either found or created.
* sfinv.get_formspec(player, context) - builds current page's formspec
* sfinv.get_nav_fs(player, context, nav, current_idx) - see above
* sfinv.make_formspec(player, context, content, show_inv, size) - adds a theme to a formspec
* show_inv, defaults to false. Whether to show the player's main inventory
* size, defaults to `size[8,8.6]` if not specified
* sfinv.register_page(name, def) - register a page, see section below
* sfinv.override_page(name, def) - overrides fields of an page registered with register_page.
* Note: Page must already be defined, (opt)depend on the mod defining it.

### sfinv Members

* pages - table of pages[pagename] = def
* pages_unordered - array table of pages in order of addition (used to build navigation tabs).
* homepage_name - name of default page
* contexts - contexts[playername] = player_context
* enabled - set to false to disable. Good for inventory rehaul mods like unified inventory

### Context

A table with these keys:

* page - current page name
* nav - a list of page names
* nav_titles - a list of page titles
* nav_idx - current nav index (in nav and nav_titles)
* any thing you want to store
* sfinv will clear the stored data on log out / log in

### sfinv.register_page

sfinv.register_page(name, def)

def is a table containing:

* `title` - human readable page name (required)
* `get(self, player, context)` - returns a formspec string. See formspec variables. (required)
* `is_in_nav(self, player, context)` - return true to show in the navigation (the tab header, by default)
* `on_player_receive_fields(self, player, context, fields)` - on formspec submit.
* `on_enter(self, player, context)` - called when the player changes pages, usually using the tabs.
* `on_leave(self, player, context)` - when leaving this page to go to another, called before other's on_enter

### get formspec

Use sfinv.make_formspec to apply a layout:

return sfinv.make_formspec(player, context, [[
list[current_player;craft;1.75,0.5;3,3;]
list[current_player;craftpreview;5.75,1.5;1,1;]
image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]
listring[current_player;main]
listring[current_player;craft]
image[0,4.25;1,1;gui_hb_bg.png]
image[1,4.25;1,1;gui_hb_bg.png]
image[2,4.25;1,1;gui_hb_bg.png]
image[3,4.25;1,1;gui_hb_bg.png]
image[4,4.25;1,1;gui_hb_bg.png]
image[5,4.25;1,1;gui_hb_bg.png]
image[6,4.25;1,1;gui_hb_bg.png]
image[7,4.25;1,1;gui_hb_bg.png]
]], true)

See above (methods section) for more options.

### Customising themes

Simply override this function to change the navigation:

function sfinv.get_nav_fs(player, context, nav, current_idx)
return "navformspec"
end

And override this function to change the layout:

function sfinv.make_formspec(player, context, content, show_inv, size)
local tmp = {
size or "size[8,8.6]",
theme_main,
sfinv.get_nav_fs(player, context, context.nav_titles, context.nav_idx),
content
}
if show_inv then
tmp[4] = theme_inv
end
return table.concat(tmp, "")
end

Stairs API
----------

1 change: 1 addition & 0 deletions mods/creative/depends.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
default
sfinv
237 changes: 4 additions & 233 deletions mods/creative/init.lua
Original file line number Diff line number Diff line change
@@ -1,237 +1,8 @@
-- minetest/creative/init.lua
dofile(minetest.get_modpath("creative") .. "/inventory.lua")

creative = {}
local player_inventory = {}
local creative_mode = minetest.setting_getbool("creative_mode")

-- Create detached creative inventory after loading all mods
creative.init_creative_inventory = function(owner)
local owner_name = owner:get_player_name()
player_inventory[owner_name] = {
size = 0,
filter = "",
start_i = 0,
tab_id = 2,
}

minetest.create_detached_inventory("creative_" .. owner_name, {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
if creative_mode and not to_list == "main" then
return count
else
return 0
end
end,
allow_put = function(inv, listname, index, stack, player)
return 0
end,
allow_take = function(inv, listname, index, stack, player)
if creative_mode then
return -1
else
return 0
end
end,
on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
end,
on_put = function(inv, listname, index, stack, player)
end,
on_take = function(inv, listname, index, stack, player)
local player_name, stack_name = player:get_player_name(), stack:get_name()
--print(player_name .. " takes item from creative inventory; listname = " .. listname .. ", index = " .. index .. ", stack = " .. dump(stack:to_table()))
if stack then
minetest.log("action", player_name .. " takes " .. stack_name .. " from creative inventory")
--print("Stack name: " .. stack_name .. ", Stack count: " .. stack:get_count())
end
end,
})

creative.update_creative_inventory(owner_name)
--print("creative inventory size: " .. player_inventory[player_name].size)
end

local function tab_category(tab_id)
local id_category = {
nil, -- Reserved for crafting tab.
minetest.registered_items,
minetest.registered_nodes,
minetest.registered_tools,
minetest.registered_craftitems
}

-- If index out of range, show default ("All") page.
return id_category[tab_id] or id_category[2]
end

function creative.update_creative_inventory(player_name)
local creative_list = {}
local player_inv = minetest.get_inventory({type = "detached", name = "creative_" .. player_name})
local inv = player_inventory[player_name]

for name, def in pairs(tab_category(inv.tab_id)) do
if not (def.groups.not_in_creative_inventory == 1) and
def.description and def.description ~= "" and
(def.name:find(inv.filter, 1, true) or
def.description:lower():find(inv.filter, 1, true)) then
creative_list[#creative_list+1] = name
end
end

table.sort(creative_list)
player_inv:set_size("main", #creative_list)
player_inv:set_list("main", creative_list)
inv.size = #creative_list
end

-- Create the trash field
local trash = minetest.create_detached_inventory("creative_trash", {
-- Allow the stack to be placed and remove it in on_put()
-- This allows the creative inventory to restore the stack
allow_put = function(inv, listname, index, stack, player)
if creative_mode then
return stack:get_count()
else
return 0
end
end,
on_put = function(inv, listname)
inv:set_list(listname, {})
end,
})
trash:set_size("main", 1)

creative.formspec_add = ""

creative.set_creative_formspec = function(player, start_i)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
local pagenum = math.floor(start_i / (3*8) + 1)
local pagemax = math.ceil(inv.size / (3*8))

player:set_inventory_formspec([[
size[8,8.6]
image[4.06,3.4;0.8,0.8;creative_trash_icon.png]
list[current_player;main;0,4.7;8,1;]
list[current_player;main;0,5.85;8,3;8]
list[detached:creative_trash;main;4,3.3;1,1;]
listring[]
tablecolumns[color;text;color;text]
tableoptions[background=#00000000;highlight=#00000000;border=false]
button[5.4,3.2;0.8,0.9;creative_prev;<]
button[7.25,3.2;0.8,0.9;creative_next;>]
button[2.1,3.4;0.8,0.5;creative_search;?]
button[2.75,3.4;0.8,0.5;creative_clear;X]
tooltip[creative_search;Search]
tooltip[creative_clear;Reset]
listring[current_player;main]
]] ..
"field[0.3,3.5;2.2,1;creative_filter;;" .. minetest.formspec_escape(inv.filter) .. "]" ..
"field_close_on_enter[creative_filter;false]" ..
"listring[detached:creative_" .. player_name .. ";main]" ..
"tabheader[0,0;creative_tabs;Crafting,All,Nodes,Tools,Items;" .. tostring(inv.tab_id) .. ";true;false]" ..
"list[detached:creative_" .. player_name .. ";main;0,0;8,3;" .. tostring(start_i) .. "]" ..
"table[6.05,3.35;1.15,0.5;pagenum;#FFFF00," .. tostring(pagenum) .. ",#FFFFFF,/ " .. tostring(pagemax) .. "]" ..
default.get_hotbar_bg(0,4.7) ..
default.gui_bg .. default.gui_bg_img .. default.gui_slots
.. creative.formspec_add
)
end

creative.set_crafting_formspec = function(player)
player:set_inventory_formspec([[
size[8,8.6]
list[current_player;craft;2,0.75;3,3;]
list[current_player;craftpreview;6,1.75;1,1;]
list[current_player;main;0,4.7;8,1;]
list[current_player;main;0,5.85;8,3;8]
list[detached:creative_trash;main;0,2.75;1,1;]
image[0.06,2.85;0.8,0.8;creative_trash_icon.png]
image[5,1.75;1,1;gui_furnace_arrow_bg.png^[transformR270]
tabheader[0,0;creative_tabs;Crafting,All,Nodes,Tools,Items;1;true;false]
listring[current_player;main]
listring[current_player;craft]
]] ..
default.get_hotbar_bg(0,4.7) ..
default.gui_bg .. default.gui_bg_img .. default.gui_slots
)
end

minetest.register_on_joinplayer(function(player)
-- If in creative mode, modify player's inventory forms
if not creative_mode then
return
end
creative.init_creative_inventory(player)
creative.set_creative_formspec(player, 0)
end)

minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" or not creative_mode then
return
end

local player_name = player:get_player_name()
local inv = player_inventory[player_name]

-- If creative is turned on mid game
if not inv then
creative.init_creative_inventory(player)
creative.set_creative_formspec(player, 0)
return
end

if fields.quit then
if inv.tab_id == 1 then
creative.set_crafting_formspec(player)
end
elseif fields.creative_tabs then
local tab = tonumber(fields.creative_tabs)
inv.tab_id = tab
player_inventory[player_name].start_i = 0

if tab == 1 then
creative.set_crafting_formspec(player)
else
creative.update_creative_inventory(player_name)
creative.set_creative_formspec(player, 0)
end
elseif fields.creative_clear then
player_inventory[player_name].start_i = 0
inv.filter = ""
creative.update_creative_inventory(player_name)
creative.set_creative_formspec(player, 0)
elseif fields.creative_search or
fields.key_enter_field == "creative_filter" then
player_inventory[player_name].start_i = 0
inv.filter = fields.creative_filter:lower()
creative.update_creative_inventory(player_name)
creative.set_creative_formspec(player, 0)
else
local start_i = player_inventory[player_name].start_i or 0

if fields.creative_prev then
start_i = start_i - 3*8
if start_i < 0 then
start_i = inv.size - (inv.size % (3*8))
if inv.size == start_i then
start_i = math.max(0, inv.size - (3*8))
end
end
elseif fields.creative_next then
start_i = start_i + 3*8
if start_i >= inv.size then
start_i = 0
end
end

player_inventory[player_name].start_i = start_i
creative.set_creative_formspec(player, start_i)
end
end)

if creative_mode then
local digtime = 42
local caps = {times = {digtime, digtime, digtime}, uses = 0, maxlevel = 256}
if minetest.setting_getbool("creative_mode") then
local digtime = 0.5
local caps = {times = {digtime, digtime, digtime}, uses = 0, maxlevel = 3}

minetest.register_item(":", {
type = "none",
171 changes: 171 additions & 0 deletions mods/creative/inventory.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
creative = {}
local player_inventory = {}

function creative.init_creative_inventory(player)
local player_name = player:get_player_name()
player_inventory[player_name] = {
size = 0,
filter = "",
start_i = 0
}

minetest.create_detached_inventory("creative_" .. player_name, {
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player2)
if not to_list == "main" then
return count
else
return 0
end
end,
allow_put = function(inv, listname, index, stack, player2)
return 0
end,
allow_take = function(inv, listname, index, stack, player2)
return -1
end,
on_move = function(inv, from_list, from_index, to_list, to_index, count, player2)
end,
on_put = function(inv, listname, index, stack, player2)
end,
on_take = function(inv, listname, index, stack, player2)
if stack and stack:get_count() > 0 then
minetest.log("action", player_name .. " takes " .. stack:get_name().. " from creative inventory")
end
end,
})

creative.update_creative_inventory(player_name, minetest.registered_items)
end

function creative.update_creative_inventory(player_name, tab_content)
local creative_list = {}
local player_inv = minetest.get_inventory({type = "detached", name = "creative_" .. player_name})
local inv = player_inventory[player_name]
if not inv then
creative.init_creative_inventory(minetest.get_player_by_name(player_name))
end

for name, def in pairs(tab_content) do
if not (def.groups.not_in_creative_inventory == 1) and
def.description and def.description ~= "" and
(def.name:find(inv.filter, 1, true) or
def.description:lower():find(inv.filter, 1, true)) then
creative_list[#creative_list+1] = name
end
end

table.sort(creative_list)
player_inv:set_size("main", #creative_list)
player_inv:set_list("main", creative_list)
inv.size = #creative_list
end

-- Create the trash field
local trash = minetest.create_detached_inventory("creative_trash", {
-- Allow the stack to be placed and remove it in on_put()
-- This allows the creative inventory to restore the stack
allow_put = function(inv, listname, index, stack, player)
return stack:get_count()
end,
on_put = function(inv, listname)
inv:set_list(listname, {})
end,
})
trash:set_size("main", 1)

creative.formspec_add = ""

function creative.register_tab(name, title, items)
sfinv.register_page("creative:" .. name, {
title = title,
is_in_nav = function(self, player, context)
return minetest.setting_getbool("creative_mode")
end,
get = function(self, player, context)
local player_name = player:get_player_name()
creative.update_creative_inventory(player_name, items)
local inv = player_inventory[player_name]
local start_i = inv.start_i or 0
local pagenum = math.floor(start_i / (3*8) + 1)
local pagemax = math.ceil(inv.size / (3*8))
return sfinv.make_formspec(player, context,
"label[6.2,3.35;" .. minetest.colorize("#FFFF00", tostring(pagenum)) .. " / " .. tostring(pagemax) .. "]" ..
[[
image[4.06,3.4;0.8,0.8;creative_trash_icon.png]
listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]
list[current_player;main;0,4.7;8,1;]
list[current_player;main;0,5.85;8,3;8]
list[detached:creative_trash;main;4,3.3;1,1;]
listring[]
button[5.4,3.2;0.8,0.9;creative_prev;<]
button[7.25,3.2;0.8,0.9;creative_next;>]
button[2.1,3.4;0.8,0.5;creative_search;?]
button[2.75,3.4;0.8,0.5;creative_clear;X]
tooltip[creative_search;Search]
tooltip[creative_clear;Reset]
listring[current_player;main]
field_close_on_enter[creative_filter;false]
]] ..
"field[0.3,3.5;2.2,1;creative_filter;;" .. minetest.formspec_escape(inv.filter) .. "]" ..
"listring[detached:creative_" .. player_name .. ";main]" ..
"list[detached:creative_" .. player_name .. ";main;0,0;8,3;" .. tostring(start_i) .. "]" ..
default.get_hotbar_bg(0,4.7) ..
default.gui_bg .. default.gui_bg_img .. default.gui_slots
.. creative.formspec_add, false)
end,
on_enter = function(self, player, context)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
if inv then
inv.start_i = 0
end
end,
on_player_receive_fields = function(self, player, context, fields)
local player_name = player:get_player_name()
local inv = player_inventory[player_name]
assert(inv)

if fields.creative_clear then
inv.start_i = 0
inv.filter = ""
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif fields.creative_search or
fields.key_enter_field == "creative_filter" then
inv.start_i = 0
inv.filter = fields.creative_filter:lower()
creative.update_creative_inventory(player_name, items)
sfinv.set_player_inventory_formspec(player, context)
elseif not fields.quit then
local start_i = inv.start_i or 0

if fields.creative_prev then
start_i = start_i - 3*8
if start_i < 0 then
start_i = inv.size - (inv.size % (3*8))
if inv.size == start_i then
start_i = math.max(0, inv.size - (3*8))
end
end
elseif fields.creative_next then
start_i = start_i + 3*8
if start_i >= inv.size then
start_i = 0
end
end

inv.start_i = start_i
sfinv.set_player_inventory_formspec(player, context)
end
end
})
end

minetest.register_on_joinplayer(function(player)
creative.init_creative_inventory(player)
end)

creative.register_tab("all", "All", minetest.registered_items)
creative.register_tab("nodes", "Nodes", minetest.registered_nodes)
creative.register_tab("tools", "Tools", minetest.registered_tools)
creative.register_tab("craftitems", "Items", minetest.registered_craftitems)
21 changes: 21 additions & 0 deletions mods/sfinv/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Simple Fast Inventory
====================

![SFINV Screeny](https://cdn.pbrd.co/images/1yQhd1TI.png)

A cleaner, simpler, solution to having an advanced inventory in Minetest.

Written by rubenwardy.
License: MIT

See game_api.txt for this mod's API

License of source code and media files:
---------------------------------------
Copyright (C) 2016 rubenwardy <rubenwardy@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
158 changes: 158 additions & 0 deletions mods/sfinv/api.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
sfinv = {
pages = {},
pages_unordered = {},
homepage_name = "sfinv:crafting",
contexts = {},
enabled = true
}

function sfinv.register_page(name, def)
assert(name, "Invalid sfinv page. Requires a name")
assert(def, "Invalid sfinv page. Requires a def[inition] table")
assert(def.get, "Invalid sfinv page. Def requires a get function.")
assert(not sfinv.pages[name], "Attempt to register already registered sfinv page " .. dump(name))

sfinv.pages[name] = def
def.name = name
table.insert(sfinv.pages_unordered, def)
end

function sfinv.override_page(name, def)
assert(name, "Invalid sfinv page override. Requires a name")
assert(def, "Invalid sfinv page override. Requires a def[inition] table")
local page = sfinv.pages[name]
assert(page, "Attempt to override sfinv page " .. dump(name) .. " which does not exist.")
for key, value in pairs(def) do
page[key] = value
end
end

function sfinv.get_nav_fs(player, context, nav, current_idx)
-- Only show tabs if there is more than one page
if #nav > 1 then
return "tabheader[0,0;tabs;" .. table.concat(nav, ",") .. ";" .. current_idx .. ";true;false]"
else
return ""
end
end

local theme_main = "bgcolor[#080808BB;true]" .. default.gui_bg ..
default.gui_bg_img

local theme_inv = default.gui_slots .. [[
list[current_player;main;0,4.7;8,1;]
list[current_player;main;0,5.85;8,3;8]
]]

function sfinv.make_formspec(player, context, content, show_inv, size)
local tmp = {
size or "size[8,8.6]",
theme_main,
sfinv.get_nav_fs(player, context, context.nav_titles, context.nav_idx),
content
}
if show_inv then
tmp[#tmp + 1] = theme_inv
end
return table.concat(tmp, "")
end

function sfinv.get_formspec(player, context)
-- Generate navigation tabs
local nav = {}
local nav_ids = {}
local current_idx = 1
for i, pdef in pairs(sfinv.pages_unordered) do
if not pdef.is_in_nav or pdef:is_in_nav(player, context) then
nav[#nav + 1] = pdef.title
nav_ids[#nav_ids + 1] = pdef.name
if pdef.name == context.page then
current_idx = i
end
end
end
context.nav = nav_ids
context.nav_titles = nav
context.nav_idx = current_idx

-- Generate formspec
local page = sfinv.pages[context.page] or sfinv.pages["404"]
if page then
return page:get(player, context)
else
local old_page = context.page
context.page = sfinv.homepage_name
assert(sfinv.pages[context.page], "[sfinv] Invalid homepage")
minetest.log("warning", "[sfinv] Couldn't find " .. dump(old_page) .. " so using switching to homepage")
return sfinv.get_formspec(player, context)
end
end

function sfinv.set_player_inventory_formspec(player, context)
if not context then
local name = player:get_player_name()
context = sfinv.contexts[name]
if not context then
context = {
page = sfinv.homepage_name
}
sfinv.contexts[name] = context
end
end

local fs = sfinv.get_formspec(player, context)
player:set_inventory_formspec(fs)
end

minetest.register_on_joinplayer(function(player)
if sfinv.enabled then
minetest.after(0.5, function()
sfinv.set_player_inventory_formspec(player)
end)
end
end)

minetest.register_on_leaveplayer(function(player)
sfinv.contexts[player:get_player_name()] = nil
end)

minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "" or not sfinv.enabled then
return false
end

-- Get Context
local name = player:get_player_name()
local context = sfinv.contexts[name]
if not context then
sfinv.set_player_inventory_formspec(player)
return false
end

-- Handle Events
if fields.tabs and context.nav then
local tid = tonumber(fields.tabs)
if tid and tid > 0 then
local id = context.nav[tid]
local page = sfinv.pages[id]
if id and page then
local oldpage = sfinv.pages[context.page]
if oldpage and oldpage.on_leave then
oldpage:on_leave(player, context)
end
context.page = id
if page.on_enter then
page:on_enter(player, context)
end
sfinv.set_player_inventory_formspec(player, context)
end
end
return
end

-- Pass to page
local page = sfinv.pages[context.page]
if page and page.on_player_receive_fields then
return page:on_player_receive_fields(player, context, fields)
end
end)
1 change: 1 addition & 0 deletions mods/sfinv/depends.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
default
22 changes: 22 additions & 0 deletions mods/sfinv/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
dofile(minetest.get_modpath("sfinv") .. "/api.lua")

sfinv.register_page("sfinv:crafting", {
title = "Crafting",
get = function(self, player, context)
return sfinv.make_formspec(player, context, [[
list[current_player;craft;1.75,0.5;3,3;]
list[current_player;craftpreview;5.75,1.5;1,1;]
image[4.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]
listring[current_player;main]
listring[current_player;craft]
image[0,4.75;1,1;gui_hb_bg.png]
image[1,4.75;1,1;gui_hb_bg.png]
image[2,4.75;1,1;gui_hb_bg.png]
image[3,4.75;1,1;gui_hb_bg.png]
image[4,4.75;1,1;gui_hb_bg.png]
image[5,4.75;1,1;gui_hb_bg.png]
image[6,4.75;1,1;gui_hb_bg.png]
image[7,4.75;1,1;gui_hb_bg.png]
]], true)
end
})

0 comments on commit d42ae71

Please sign in to comment.