Friend asked me about code to keep ‘auto loot lists’ in storage.
(Player can configure few lists of items and then just switch between them, when he goes to other spawn with different loot.)
Thing he needed was something like c++ std::set, but in Lua. With default configuration player can keep up to 10 lists of up to 100 unique numbers (in my friend case - item ids).
Maybe someone need something similar or want to learn some programming by reading this algorithm.
Lists are kept in player storage in format:
Some other rules:
I also wrote tests for these functions. Tests that I can run without OTS. I often use Online Lua Compiler - Online Lua Editor - Online Lua IDE - Lua Coding Online - Practice Lua Online - Execute Lua Online - Compile Lua Online - Run Lua Online (https://www.tutorialspoint.com/execute_lua_online.php) to run code like this. In this case I had to create 'fake player object', to make it get/set storages:
(Player can configure few lists of items and then just switch between them, when he goes to other spawn with different loot.)
Thing he needed was something like c++ std::set, but in Lua. With default configuration player can keep up to 10 lists of up to 100 unique numbers (in my friend case - item ids).
Maybe someone need something similar or want to learn some programming by reading this algorithm.
Lists are kept in player storage in format:
- first element of list is number of elements in list
- next elements are elements of list
Some other rules:
- adding elements with duplicated value does nothing (unique list)
- removing element from list move all 'next elements' one position closer to start of list, there can't be gaps in list
Lua:
-- config
local listsStartStorage = 550000000
local maximumListsCount = 10
local maximumElementsPerList = 100
-- variables for calculations
local listOffset = maximumElementsPerList + 1
function lists_getLists(player)
local result = {}
for i = 1, maximumListsCount do
result[i] = lists_getListElementsCount(player, i)
end
return result
end
function lists_getListElementsCount(player, listId)
local startStorage = listsStartStorage + listOffset * listId
return math.max(0, player:getStorage(startStorage))
end
function lists_getListElements(player, listId)
local result = {}
local startStorage = listsStartStorage + listOffset * listId
local listElementsCount = lists_getListElementsCount(player, listId)
for i = startStorage + 1, startStorage + listElementsCount do
table.insert(result, player:getStorage(i))
end
return result
end
function lists_removeAllListElements(player, listId)
local startStorage = listsStartStorage + listOffset * listId
local listElementsCount = lists_getListElementsCount(player, listId)
for i = startStorage + 1, startStorage + listElementsCount + 1 do
player:setStorage(i, -1)
end
player:setStorage(startStorage, -1)
end
function lists_getListElement(player, listId, elementKey)
local elementStorage = listsStartStorage + listOffset * listId + elementKey
return player:getStorage(elementStorage)
end
local function lists_assertListId(listId)
assert(listId >= 1, 'minimum list id is 1')
assert(listId <= maximumListsCount, 'maximum list id is 1' .. maximumListsCount)
end
local function lists_assertElementKey(elementKey)
assert(elementKey >= 1, 'minimum list element id is 1')
assert(elementKey <= maximumElementsPerList, 'maximum list element id is ' .. maximumElementsPerList)
end
-- this is for internal use only, should not be used by user
local function lists_setListElement(player, listId, elementKey, elementValue)
lists_assertListId(listId)
lists_assertElementKey(elementKey)
local elementStorage = listsStartStorage + listOffset * listId + elementKey
player:setStorage(elementStorage, elementValue)
end
-- this is for internal use only, should not be used by user
local function lists_setListElementsCount(player, listId, count)
lists_assertListId(listId)
lists_assertElementKey(count)
local startStorage = listsStartStorage + listOffset * listId
player:setStorage(startStorage, count)
end
function lists_addListElement(player, listId, elementValue)
local elements = lists_getListElements(player, listId)
for k, v in pairs(elements) do
if v == elementValue then
return
end
end
local elementsCount = lists_getListElementsCount(player, listId)
lists_setListElement(player, listId, elementsCount + 1, elementValue)
lists_setListElementsCount(player, listId, elementsCount + 1)
end
function lists_removeListElement(player, listId, elementValue)
local elements = lists_getListElements(player, listId)
local elementToRemovePosition = nil
for k, v in pairs(elements) do
if v == elementValue then
elementToRemovePosition = k
break
end
end
if elementToRemovePosition then
local elementsCount = lists_getListElementsCount(player, listId)
for i = elementToRemovePosition + 1, elementsCount do
local nextElementValue = lists_getListElement(player, listId, i)
lists_setListElement(player, listId, i - 1, nextElementValue)
end
lists_setListElement(player, listId, elementsCount, -1)
lists_setListElementsCount(player, listId, elementsCount - 1)
end
end
I also wrote tests for these functions. Tests that I can run without OTS. I often use Online Lua Compiler - Online Lua Editor - Online Lua IDE - Lua Coding Online - Practice Lua Online - Execute Lua Online - Compile Lua Online - Run Lua Online (https://www.tutorialspoint.com/execute_lua_online.php) to run code like this. In this case I had to create 'fake player object', to make it get/set storages:
Lua:
Player = {}
function Player:new()
o = {storages = {}}
setmetatable(o, self)
self.__index = self
return o
end
function Player.getStorage(self, k)
if (self.storages[k]) then
return self.storages[k]
end
return -1
end
function Player.setStorage(self, k, v)
if (v == -1) then
v = nil
end
self.storages[k] = v
end
function Player.dumpStorages(self)
local storages = 'storages: '
for k, v in pairs(self.storages) do
storages = storages .. k .. '=' .. v .. ', '
end
print(storages)
end
local function printPlayerListsElementsCount(player)
local playerLists = lists_getLists(player)
for k, v in pairs(playerLists) do
local listElementsString = ''
for k2, v2 in pairs(lists_getListElements(player, k)) do
listElementsString = listElementsString .. ' ' .. k2 .. '=' .. v2 .. ', '
end
print ('list', k, 'elements', v, 'values', listElementsString)
end
end
player = Player:new()
print()
player:dumpStorages()
print('start - empty list')
printPlayerListsElementsCount(player)
print()
player:dumpStorages()
lists_addListElement(player, 2, 2001)
lists_addListElement(player, 2, 2002)
print('added 2 elements to list 2')
player:dumpStorages()
printPlayerListsElementsCount(player)
print()
player:dumpStorages()
lists_addListElement(player, 1, 1001)
lists_addListElement(player, 1, 1002)
lists_addListElement(player, 1, 1003)
lists_addListElement(player, 1, 1004)
lists_addListElement(player, 1, 1005)
print('added 5 elements to list 1')
player:dumpStorages()
printPlayerListsElementsCount(player)
print()
player:dumpStorages()
lists_removeListElement(player, 1, 1001)
print('removed first element from list 1')
player:dumpStorages()
printPlayerListsElementsCount(player)
print()
player:dumpStorages()
lists_removeListElement(player, 1, 1005)
print('removed last element from list 1')
player:dumpStorages()
printPlayerListsElementsCount(player)
print()
player:dumpStorages()
lists_removeListElement(player, 1, 1003)
print('removed middle element from list 1')
player:dumpStorages()
printPlayerListsElementsCount(player)
print()
player:dumpStorages()
lists_removeAllListElements(player, 1)
print('removed all elements from list 1')
player:dumpStorages()