├── README.md ├── latest_version.txt ├── media └── lua │ ├── client │ ├── bcUtils_client.lua │ └── bcUtils_genericTA.lua │ └── shared │ └── bcUtils.lua ├── mod.info └── tiny_avc.txt /README.md: -------------------------------------------------------------------------------- 1 | # bcUtils # 2 | 3 | This is a collection of helper functions useful for modding Project Zomboid. 4 | 5 | ## Custom Classes ## 6 | ### BCUGenericTA ### 7 | This is an extensible TimedAction that can be used to implement timed actions without having to implement an entire class for it. Simple things can be done using this action in very little code. 8 | Example: 9 | 10 | ta = BCUGenericTA:new(getPlayer(), 60); -- new TimedAction with current player and a duration of 60 11 | ta:setIsValid(taIsValid, param1, param2, param3); -- before this TA is created, the function taIsValid is called with the parameters param1, param2 and param3. If this function does not return true, the TA is not created. 12 | ta:setOnStart(taOnStart, param1); -- at the start of this TA, the function taOnStart is called with the parameter param1. 13 | ta:setOnStop(taOnStop); -- if this TA is interrupted (not finished), the function taOnStop is called without parameters. 14 | ta:setOnUpdate(taOnUpdate); -- Every updatetick, the function taOnUpdate is called without parameters. 15 | ta:setOnPerform(taOnPerform, param1); -- When the TA finishes successfully, the function taOnPerform is called with parameter param1 16 | ISTimedActionQueue.add(ta); -- add this TA to the queue and start it. 17 | 18 | Every set\* parameter can take a variable number of arguments, from 0 arguments to a - theoretically - infinite number of arguments. **ta:setOnStart(taOnStart);** is just as valid as **ta:setOnStart(taOnStart, param1, param2, param3, param4, param5, param6, param7, param8, param9);**. 19 | The function set via the set\* function will have their **self** variable set to the TimedAction object, so this is valid: 20 | 21 | function taOnUpdate() 22 | self.counter = self.counter + 1; 23 | end 24 | ta = BCUGenericTA:new(getPlayer(), 60); 25 | ta.counter = 0; 26 | ta:setOnUpdate(taOnUpdate); 27 | 28 | ## Generic functions ## 29 | ### bcUtils.dump ### 30 | This funtion returns the contents of a variable or table in a human readable format useful for debugging. 31 | Example: 32 | 33 | t = {} 34 | t.a = 123 35 | t.b = "abc" 36 | t.c = {} 37 | t.c.d = 456 38 | t.c.e = "def" 39 | print(bcUtils.dump(variable)); 40 | 41 | Result: 42 | 43 | { 44 | [a] = 123, 45 | [c] = { 46 | [a] = 456, 47 | [b] = "def", 48 | } 49 | , 50 | [b] = "abc", 51 | }, 52 | 53 | ### bcUtils.pline ### 54 | This function simply prints its parameter to the logfile, converting it to a string first. 55 | Example: 56 | 57 | bcUtils.pline(getPlayer()); 58 | 59 | ### bcUtils.cloneTable ### 60 | This function creates a deep copy of a table. The return value is a copy of the original table, instead of a pointer to it. 61 | Example: 62 | 63 | table1 = { a = 123, b = 456 }; 64 | table2 = table1; 65 | table2.a = 1000; 66 | print(table1.a); -- prints 1000 67 | print(table2.a); -- prints 1000 68 | 69 | table1 = { a = 123, b = 456 }; 70 | table2 = bcUtils.cloneTable(table1); 71 | table2.a = 1000; 72 | print(table1.a); -- prints 123 73 | print(table2.a); -- prints 1000 74 | 75 | ### bcUtils.tableIsEmpty ### 76 | This function checks if a table is empty, ie: has no key at all. 77 | Example: 78 | 79 | table1 = {}; 80 | table1 == {} -- returns false, because these are two different tables 81 | bcUtils.tableIsEmpty(table1); -- returns true, because table1 has no keys 82 | table1.a = 123; 83 | bcUtils.tableIsEmpty(table1); -- returns false, because table1 has a key "a" 84 | 85 | ### bcUtils.tableIsEqual ### 86 | This function does a deep comparison of two tables and checks if all their keys exist in the other and all values of all keys are identical. 87 | Example: 88 | 89 | table1 = { a = 1, b = 2, c = 3}; 90 | table2 = { a = 1, b = 2, c = 3}; 91 | table1 == table2 -- returns false, because these are two different tables 92 | bcUtils.tableIsEqual(table1, table2); -- returns true, because the tables have identical keys and these have identical values 93 | 94 | 95 | ### bcUtils.hasDirtRoad ### 96 | This function checks an IsoGridSquare for the existance of a dirtroad tile. 97 | Example: 98 | 99 | bcUtils.hasDirtRoad(getCell():getGridSquare(x, y, z)); 100 | 101 | ### bcUtils.hasStreet ### 102 | This function checks an IsoGridSquare for the existance of a street tile. 103 | Example: 104 | 105 | bcUtils.hasStreet(getCell():getGridSquare(x, y, z)); 106 | 107 | ### bcUtils.isContainer ### 108 | This function checks if a worlditem is a container (eg: shelf, cabinet). 109 | Example: 110 | 111 | objects = gridsquare:getObjects(); 112 | for x=0,objects:size()-1 do 113 | if bcUtils.isContainer(objects:get(x)) then 114 | bcUtils.pline(bcUtils.dump(objects:get(x))); -- print a dump of the container object 115 | end 116 | end 117 | 118 | ### bcUtils.isDirtRoad ### 119 | This function checks if a worlditem is a dirtroad. The hasDirtRoad function uses this. Example: 120 | 121 | objects = gridsquare:getObjects(); 122 | for x=0,objects:size()-1 do 123 | if bcUtils.isDirtRoad(objects:get(x)) then 124 | bcUtils.pline(bcUtils.dump(objects:get(x))); -- print a dump of the dirtroad object 125 | end 126 | end 127 | 128 | ### bcUtils.isStreet ### 129 | This function checks if a worlditem is a street. The hasStreet function uses this. Example: 130 | 131 | objects = gridsquare:getObjects(); 132 | for x=0,objects:size()-1 do 133 | if bcUtils.isStreet(objects:get(x)) then 134 | bcUtils.pline(bcUtils.dump(objects:get(x))); -- print a dump of the street object 135 | end 136 | end 137 | 138 | ### bcUtils.isDoor ### 139 | This function checks if a worlditem is a door. 140 | Example: 141 | 142 | objects = gridsquare:getObjects(); 143 | for x=0,objects:size()-1 do 144 | if bcUtils.isDoor(objects:get(x)) then 145 | bcUtils.pline(bcUtils.dump(objects:get(x))); -- print a dump of the door object 146 | end 147 | end 148 | 149 | ### bcUtils.isStove ### 150 | This function checks if a worlditem is a stove. 151 | Example: 152 | 153 | objects = gridsquare:getObjects(); 154 | for x=0,objects:size()-1 do 155 | if bcUtils.isStove(objects:get(x)) then 156 | bcUtils.pline(bcUtils.dump(objects:get(x))); -- print a dump of the stove object 157 | end 158 | end 159 | 160 | ### bcUtils.isWindow ### 161 | This function checks if a worlditem is a window. 162 | Example: 163 | 164 | objects = gridsquare:getObjects(); 165 | for x=0,objects:size()-1 do 166 | if bcUtils.isWindow(objects:get(x)) then 167 | bcUtils.pline(bcUtils.dump(objects:get(x))); -- print a dump of the window object 168 | end 169 | end 170 | 171 | ### bcUtils.isTree ### 172 | This function checks if a worlditem is a tree. 173 | Example: 174 | 175 | objects = gridsquare:getObjects(); 176 | for x=0,objects:size()-1 do 177 | if bcUtils.isTree(objects:get(x)) then 178 | bcUtils.pline(bcUtils.dump(objects:get(x))); -- print a dump of the tree object 179 | end 180 | end 181 | 182 | ### bcUtils.realDist ### 183 | This function returns the real, direct distance between two coordinates using the pythagorean formula. 184 | Example: 185 | 186 | if bcUtils.realDist(player:getX(), player:getY(), gridsquare:getX(), gridsquare:getY()) <= range then 187 | -- do something 188 | end 189 | 190 | ### bcUtils.split ### 191 | Splits a string into an array using a provided separator. 192 | Example: 193 | 194 | bcUtils.pline(bcUtils.dump(bcUtils.split("abc,def,ghi,jkl", ","))) 195 | 196 | Result: 197 | 198 | { 199 | [1] = abc, 200 | [2] = def, 201 | [3] = ghi, 202 | [4] = jkl, 203 | }, 204 | 205 | ### bcUtils.numUses ### 206 | This function returns the number of uses in a Drainable item, assuming a full item. 207 | Example: 208 | 209 | local item = getPlayer():getInventory():FindAndReturn("Base.Twine"); 210 | bcUtils.pline(bcUtils.numUses(item)); 211 | 212 | Result: 213 | 214 | 5 215 | 216 | ### bcUtils.numUsesLeft ### 217 | This function returns the remaining uses in a specific Drainable item as specified by its current fill level. 218 | Example: 219 | 220 | local item = getPlayer():getInventory():FindAndReturn("Base.Twine"); 221 | bcUtils.pline(bcUtils.numUsesLeft(item)); 222 | 223 | Result: 224 | 225 | 3 226 | 227 | ### bcUtils.writeINI ### 228 | This functions write a Lua table into a file in ini style. 229 | Example: 230 | 231 | local t = {}; 232 | t.main = {}; 233 | t.main.a = 123; 234 | t.main.b = "abc"; 235 | t.secondary = {}; 236 | t.secondary.a = 1000; 237 | t.secondary.b = "Hello world!"; 238 | bcUtils.writeINI("test.ini", t); 239 | 240 | The resulting file Zomboid/Lua/test.ini looks like this: 241 | 242 | [main] 243 | a=123 244 | b=abc 245 | [secondary] 246 | a=1000 247 | b=Hello world! 248 | 249 | Note that this isn't really 100% INI style, but close enough to be usable. 250 | 251 | ### bcUtils.readINI ### 252 | This functions reads an ini style file and returns its content as a Lua table. 253 | Example (reading the file created above): 254 | 255 | local t = bcUtils.readINI("test.ini"); 256 | t.main.a == "123"; -- true 257 | t.main.b == "abc"; -- true 258 | t.secondary.a == "1000"; -- true 259 | t.secondary.b == "Hello world!"; -- true 260 | 261 | Note that all read values are returned as strings. No implicit number conversion is done. 262 | -------------------------------------------------------------------------------- /latest_version.txt: -------------------------------------------------------------------------------- 1 | version:0.1.1 2 | minVersion:32.14 3 | -------------------------------------------------------------------------------- /media/lua/client/bcUtils_client.lua: -------------------------------------------------------------------------------- 1 | require "bcUtils" 2 | require "OptionScreens/MainScreen" 3 | require "ISUI/ISButton" 4 | 5 | if not bcUtils then bcUtils = {} end 6 | 7 | bcUtils.reloadLua = function() -- {{{ 8 | getCore():ResetLua(true, "modsChanged") -- Boom! 9 | end 10 | -- }}} 11 | bcUtils.initMainMenu = function() -- {{{ 12 | bcUtils.forceReloadLuaButton = ISButton:new(MainScreen.instance.width-150, 50, 150, 25, "Forcereload LUA", nil, bcUtils.reloadLua); 13 | bcUtils.forceReloadLuaButton.borderColor = {r=1, g=1, b=1, a=0.1}; 14 | bcUtils.forceReloadLuaButton:ignoreWidthChange(); 15 | bcUtils.forceReloadLuaButton:ignoreHeightChange(); 16 | bcUtils.forceReloadLuaButton:setAnchorLeft(false); 17 | bcUtils.forceReloadLuaButton:setAnchorRight(true); 18 | bcUtils.forceReloadLuaButton:setAnchorTop(true); 19 | bcUtils.forceReloadLuaButton:setAnchorBottom(false); 20 | 21 | MainScreen.instance:addChild(bcUtils.forceReloadLuaButton); 22 | end 23 | -- }}} 24 | Events.OnMainMenuEnter.Add(bcUtils.initMainMenu); 25 | 26 | -- TODO These MUST go elsewhere TODO 27 | -- These are hotfixes for missing functionality in Kahlua 28 | if table.pack == nil then 29 | table.pack = function(...) 30 | return { n = select("#", ...), ... } 31 | end 32 | end 33 | if table.unpack == nil then 34 | table.unpack = function(t, i) 35 | i = i or 1; 36 | if t[i] then 37 | return t[i], unpack(t, i + 1) 38 | end 39 | end 40 | end 41 | 42 | -------------------------------------------------------------------------------- /media/lua/client/bcUtils_genericTA.lua: -------------------------------------------------------------------------------- 1 | require "TimedActions/ISBaseTimedAction" 2 | 3 | BCUGenericTA = ISBaseTimedAction:derive("BCUGenericTA"); 4 | function BCUGenericTA:isValid() -- {{{ 5 | if self.onIsValid then return self:onIsValid(table.unpack(self.onIsValidArguments)); end 6 | return true; 7 | end 8 | -- }}} 9 | function BCUGenericTA:setOnIsValid(func, ...) -- {{{ 10 | self.onIsValid = func; 11 | self.onIsValidArguments = {}; 12 | for i,v in pairs(table.pack(...)) do 13 | self.onIsValidArguments[i] = v; 14 | end 15 | end 16 | -- }}} 17 | 18 | function BCUGenericTA:update() -- {{{ 19 | if self.onUpdate then self:onUpdate(table.unpack(self.onUpdateArguments)); end 20 | end 21 | -- }}} 22 | function BCUGenericTA:setOnUpdate(func, ...) -- {{{ 23 | self.onUpdate = func; 24 | self.onUpdateArguments = {}; 25 | for i,v in pairs(table.pack(...)) do 26 | self.onUpdateArguments[i] = v; 27 | end 28 | end 29 | -- }}} 30 | 31 | function BCUGenericTA:start() -- {{{ 32 | if self.onStart then self:onStart(table.unpack(self.onStartArguments)); end 33 | end 34 | -- }}} 35 | function BCUGenericTA:setOnStart(func, ...) -- {{{ 36 | self.onStart = func; 37 | self.onStartArguments = {}; 38 | for i,v in pairs(table.pack(...)) do 39 | self.onStartArguments[i] = v; 40 | end 41 | end 42 | -- }}} 43 | 44 | function BCUGenericTA:stop() -- {{{ 45 | if self.onStop then self:onStop(table.unpack(self.onStopArguments)); end 46 | ISBaseTimedAction.stop(self); 47 | end 48 | -- }}} 49 | function BCUGenericTA:setOnStop(func, ...) -- {{{ 50 | self.onStop = func; 51 | self.onStopArguments = {}; 52 | for i,v in pairs(table.pack(...)) do 53 | self.onStopArguments[i] = v; 54 | end 55 | end 56 | -- }}} 57 | 58 | function BCUGenericTA:perform() -- {{{ 59 | if self.onPerform then self:onPerform(table.unpack(self.onPerformArguments)); end 60 | -- needed to remove from queue / start next. 61 | ISBaseTimedAction.perform(self); 62 | end 63 | -- }}} 64 | 65 | function BCUGenericTA:setOnPerform(func, ...) -- {{{ 66 | self.onPerform = func; 67 | self.onPerformArguments = {}; 68 | for i,v in pairs(table.pack(...)) do 69 | self.onPerformArguments[i] = v; 70 | end 71 | end 72 | -- }}} 73 | 74 | function BCUGenericTA:new(character, time) -- {{{ 75 | local o = {} 76 | 77 | setmetatable(o, self) 78 | self.__index = self 79 | o.character = character; 80 | o.stopOnWalk = true; 81 | o.stopOnRun = true; 82 | o.maxTime = time; 83 | 84 | return o; 85 | end 86 | -- }}} 87 | -------------------------------------------------------------------------------- /media/lua/shared/bcUtils.lua: -------------------------------------------------------------------------------- 1 | require "luautils" 2 | 3 | if not bcUtils then bcUtils = {} end 4 | bcUtils.dump = function(o, lvl, ind) -- {{{ Small function to dump an object. 5 | if lvl == nil then lvl = 5 end 6 | if ind == nil then ind = 0 end 7 | 8 | local x; 9 | local pref = ""; 10 | for x=1,ind do 11 | pref = pref .. " "; 12 | end 13 | 14 | if lvl < 0 then return pref .. "SO ("..tostring(o)..")" end 15 | 16 | if type(o) == 'table' then 17 | local s = '{\n'; 18 | for k,v in pairs(o) do 19 | if k == "prev" or k == "next" then 20 | s = s .. pref .. '['..k..'] = '..tostring(v)..",\n"; 21 | else 22 | if type(k) ~= 'number' then k = '"'..tostring(k)..'"' end 23 | s = s .. pref .. '['..k..'] = ' .. bcUtils.dump(v, lvl - 1, ind + 1) .. ',\n' 24 | end 25 | end 26 | pref = ""; 27 | for x=2,ind do 28 | pref = pref .. " "; 29 | end 30 | return s .. pref .. '}\n' -- TODO Maybe remove the \n here? 31 | else 32 | if type(o) == "string" then return '"'..tostring(o)..'"' end 33 | return tostring(o) 34 | end 35 | end 36 | -- }}} 37 | bcUtils.pline = function (text) -- {{{ Print text to logfile 38 | print(tostring(text)); 39 | end 40 | -- }}} 41 | bcUtils.isStove = function(o) -- {{{ -- Check if an item is a stove 42 | if not o then return false end; 43 | return instanceof(o, "IsoStove"); 44 | end 45 | -- }}} 46 | bcUtils.isWindow = function(o) -- {{{ -- check if an item is a window 47 | if not o then return false end; 48 | return instanceof(o, "IsoWindow"); 49 | end 50 | -- }}} 51 | bcUtils.isDoor = function(o) -- {{{ check if an item is a door 52 | if not o then return false end; 53 | return (instanceof(o, "IsoDoor") or (instanceof(o, "IsoThumpable") and o:isDoor())) 54 | end 55 | -- }}} 56 | bcUtils.isTree = function(o) -- {{{ check if an item is a tree 57 | if not o then return false end; 58 | return instanceof(o, "IsoTree"); 59 | end 60 | -- }}} 61 | bcUtils.isContainer = function(o) -- {{{ check if an item is a container 62 | if not o then return false end; 63 | return o:getContainer(); 64 | end 65 | -- }}} 66 | bcUtils.isPenOrPencil = function(o) -- {{{ check if an item is a pen or pencil 67 | if not o then return false end; 68 | return o:getFullType() == "Base.Pen" or o:getFullType() == "Base.Pencil"; 69 | end 70 | -- }}} 71 | bcUtils.isMap = function(o) -- {{{ check if an item is a map 72 | if not o then return false end; 73 | return o:getFullType() == "BCMapMod.Map"; 74 | end 75 | -- }}} 76 | bcUtils.tableIsEmpty = function(o) -- {{{ check if a passed table is empty (ie: {} ) 77 | for _,_ in pairs(o) do 78 | return false 79 | end 80 | return true 81 | end 82 | -- }}} 83 | bcUtils.tableIsEqual = function(tbl1, tbl2) -- {{{ check if two tables have identical content 84 | for k,v in pairs(tbl1) do 85 | if type(v) == "table" and type(tbl2[k]) == "table" then 86 | if not bcUtils.tableIsEqual(v, tbl2[k]) then return false end 87 | else 88 | if v ~= tbl2[k] then return false end 89 | end 90 | end 91 | for k,v in pairs(tbl2) do 92 | if type(v) == "table" and type(tbl1[k]) == "table" then 93 | if not bcUtils.tableIsEqual(v, tbl1[k]) then return false end 94 | else 95 | if v ~= tbl1[k] then return false end 96 | end 97 | end 98 | return true 99 | end 100 | -- }}} 101 | bcUtils.cloneTable = function(orig) -- {{{ clone a table 102 | local orig_type = type(orig) 103 | local copy 104 | if orig_type == 'table' then 105 | copy = {} 106 | for orig_key,orig_value in pairs(orig) do 107 | copy[orig_key] = bcUtils.cloneTable(orig_value) 108 | end 109 | setmetatable(copy, bcUtils.cloneTable(getmetatable(orig))) 110 | else -- number, string, boolean, etc 111 | copy = orig 112 | end 113 | return copy 114 | end 115 | -- }}} 116 | bcUtils.isStreet = function(o) -- {{{ check if an item is a street 117 | if not o then return false end 118 | if not o:getTextureName() then return false end 119 | return luautils.stringStarts(o:getTextureName(), "blends_street"); 120 | end 121 | -- }}} 122 | bcUtils.hasStreet = function(o) -- {{{ chcek if a tile has a street on it 123 | if not o then return false end 124 | local objects = o:getObjects(); 125 | for k=0,objects:size()-1 do 126 | local it = objects:get(k); 127 | if bcUtils.isStreet(it) then 128 | return true; 129 | end 130 | end 131 | return false 132 | end 133 | -- }}} 134 | bcUtils.isDirtRoad = function(o) -- {{{ check if an item is a dirtroad 135 | if not o then return false end 136 | if not o:getTextureName() then return false end 137 | if luautils.stringStarts(o:getTextureName(), "blends_natural") then 138 | local m = bcUtils.split(o:getTextureName(), "_"); 139 | return m[3] == "01" and tonumber(m[4]) <= 7; 140 | end 141 | return false 142 | end 143 | -- }}} 144 | bcUtils.hasDirtRoad = function(o) -- {{{ check if a tile has a dirtroad on it 145 | if not o then return false end 146 | local objects = o:getObjects(); 147 | for k=0,objects:size()-1 do 148 | local it = objects:get(k); 149 | if bcUtils.isDirtRoad(it) then 150 | return true; 151 | end 152 | end 153 | return false 154 | end 155 | -- }}} 156 | bcUtils.realDist = function(x1, y1, x2, y2) -- {{{ check real distance between two tiles 157 | return math.sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)) 158 | end 159 | -- }}} 160 | bcUtils.split = function(string, sep) -- {{{ split a string, regex style 161 | sep = sep or ":"; 162 | local pattern = string.format("([^%s]+)", sep); 163 | local fields = {}; 164 | string:gsub(pattern, function(c) fields[#fields+1] = c end); 165 | return fields 166 | end 167 | -- }}} 168 | bcUtils.readModINI = function(mod, filename)--{{{ 169 | local retVal = {}; 170 | local rvptr = retVal; 171 | local f = getModFileReader(mod, filename, false); 172 | if not f then return retVal end; 173 | 174 | local line = "1"; 175 | local currentCat = "unknown"; 176 | 177 | while line do 178 | line = f:readLine(); 179 | if line then 180 | if luautils.stringStarts(line, "[") then 181 | currentCat = string.match(line, "[a-zA-Z0-9/ \.]+"); 182 | rvptr = retVal; 183 | for _,cat in ipairs(bcUtils.split(currentCat, "/")) do 184 | if not rvptr[cat] then rvptr[cat] = {} end 185 | rvptr = rvptr[cat]; 186 | end 187 | else 188 | local kv = bcUtils.split(line, "="); 189 | rvptr[kv[1]] = kv[2]; 190 | end 191 | end 192 | end 193 | return retVal; 194 | end 195 | --}}} 196 | bcUtils.readINI = function(filename)--{{{ 197 | local retVal = {}; 198 | local rvptr = retVal; 199 | local f = getFileReader(filename, false); 200 | if not f then return retVal end; 201 | 202 | local line = "1"; 203 | local currentCat = "unknown"; 204 | 205 | while line do 206 | line = f:readLine(); 207 | if line then 208 | if luautils.stringStarts(line, "[") then 209 | currentCat = string.match(line, "[a-zA-Z0-9/ \.]+"); 210 | rvptr = retVal; 211 | for _,cat in ipairs(bcUtils.split(currentCat, "/")) do 212 | if not rvptr[cat] then rvptr[cat] = {} end 213 | rvptr = rvptr[cat]; 214 | end 215 | else 216 | local kv = bcUtils.split(line, "="); 217 | rvptr[kv[1]] = kv[2]; 218 | end 219 | end 220 | end 221 | return retVal; 222 | end 223 | --}}} 224 | bcUtils.writeINItable = function(fd, table, parentCategory)--{{{ 225 | local category; 226 | for catID,catVal in pairs(table) do 227 | if parentCategory then 228 | category = parentCategory.."/"..catID; 229 | else 230 | category = catID; 231 | end 232 | fd:write("["..category.."]\n"); 233 | for k,v in pairs(catVal) do 234 | if type(v) == "table" then 235 | local a = {}; 236 | a[k] = v; 237 | bcUtils.writeINItable(fd, a, category); 238 | else 239 | fd:write(tostring(k).."="..tostring(v).."\n"); 240 | end 241 | end 242 | end 243 | end 244 | --}}} 245 | bcUtils.writeINI = function(filename, content)--{{{ 246 | local fd = getFileWriter(filename, true, false); -- create if not exist, do not append but overwrite 247 | if not fd then return false end; 248 | bcUtils.writeINItable(fd, content); 249 | fd:close(); 250 | end 251 | --}}} 252 | 253 | bcUtils.numUses = function(item) -- {{{ returns number of uses in a Drainable 254 | if not item then return 0 end 255 | return math.floor(1 / item:getUseDelta()); 256 | end 257 | -- }}} 258 | bcUtils.numUsesLeft = function(item) -- {{{ returns remaining uses in a Drainable 259 | if not item then return 0 end 260 | return math.floor(item:getUsedDelta() / item:getUseDelta()); 261 | end 262 | -- }}} 263 | -------------------------------------------------------------------------------- /mod.info: -------------------------------------------------------------------------------- 1 | name=blindcoders utility functions. 2 | poster=empty.png 3 | description=A collection of functions blindcoder regularly uses in his mods. 4 | id=bcUtils 5 | 6 | modversion=1.2.0 7 | pzversion=32.24 8 | versionurl=https://raw.githubusercontent.com/blind-coder/pz-bcUtils/master/mod.info 9 | -------------------------------------------------------------------------------- /tiny_avc.txt: -------------------------------------------------------------------------------- 1 | version:0.1.1 2 | url:https://raw.githubusercontent.com/blind-coder/pz-bcUtils/master/latest_version.txt 3 | --------------------------------------------------------------------------------