local hf = eCore.helper function getPlayer(player) if type(player) == 'table' then return player end return tonumber(player) and eCore:getPlayer(tonumber(player)) or false end function accessToRemove(data, playerData) if not data.workstation then -- if recipe data then return return false end if type(data.owner) ~= 'table' then -- if not portable then return return false end if Config.canRemove.everybody then return true end if playerData.identifier == data.owner.identifier then return true end if Config.canRemove.ownerJob and playerData.job.name ~= 'unemployed' and playerData.job.name == data.owner.jobName then return true end if Config.canRemove.ownerGang and not hf.isEmpty(playerData.gang) and playerData.gang.name ~= 'none' and playerData.gang.name == data.owner.gangName then return true end if hf.isPopulatedTable(Config.canRemove.supervisoryJobs) then if hf.inTable(playerData.job.name, Config.canRemove.supervisoryJobs) then return true end end return false end function accessToUsePortable(data, playerData) if playerData.identifier == data.owner.identifier then return true end if Config.canUse.everybody then return true end if Config.canUse.ownerJob and data.owner.jobName ~= 'unemployed' and playerData.job.name == data.owner.jobName then return true end if playerData.gang and Config.canUse.ownerGang and data.owner.gangName ~= 'none' and playerData.gang.name == data.owner.gangName then return true end return false end function accessManagement(data, playerData, playerAcePermissions) return { accessToUse = accessToUse(data, playerData, playerAcePermissions), accessToRemove = accessToRemove(data, playerData), } end function accessToUse(data, playerData, playerAcePermissions) if data.requiredAcePermission then if type(playerAcePermissions) ~= 'table' then playerAcePermissions = {} end if not playerAcePermissions[data.requiredAcePermission] then return false end end if data.workstation and type(data.owner) == 'table' then if not accessToUsePortable(data, playerData) then return false end end if not hf.isPopulatedTable(data.whitelist) and not hf.isPopulatedTable(data.blacklist) then return true end local authorized = false if hf.isPopulatedTable(data.whitelist) then local jobNameInWhitelist = hf.inTable(playerData.job.name, data.whitelist) local gangNameInWhitelist = playerData.gang and hf.inTable(playerData.gang.name, data.whitelist) or false authorized = jobNameInWhitelist or gangNameInWhitelist if not authorized then local level = data.whitelist[playerData.job.name] if level then authorized = hf.isPopulatedTable(level) and hf.inTable(playerData.job.grade, level) or true end end if not authorized and playerData.gang then local level = data.whitelist[playerData.gang.name] if level then authorized = hf.isPopulatedTable(level) and hf.inTable(playerData.gang.grade, level) or true end end elseif hf.isPopulatedTable(data.blacklist) then local jobNameInBlacklist = hf.inTable(playerData.job.name, data.blacklist) local gangNameInBlacklist = playerData.gang and hf.inTable(playerData.gang.name, data.blacklist) or false authorized = not (jobNameInBlacklist or gangNameInBlacklist) end return authorized end function initMeta(playerId) if Config.systemMode.profession and hf.isPopulatedTable(Config.recipes) then local allProficiency = {} for _, recipe in pairs(Config.recipes) do allProficiency[recipe.profession] = 0 end exports.e_core:registerMeta(playerId, 'crafting', allProficiency) end if Config.systemMode.blueprint then exports.e_core:registerMeta(playerId, 'knowledge', { blueprints = {} }) end end function sessionReset() ECO.SESSION = { inProgress = false, sid = false, productName = '', productLabel = '', recipeTime = 10, productRequest = 0, productDone = 0, productionTime = 5, profession = '', level = 0 } end function setAction(zoneId) ECO.ACTION = {} if not Config.workstations[zoneId] then ECO.ACTION.error = 'not_in_the_workspace' return false end playerData = eCore:getPlayer() if not eCore:canInteract(playerData) then ECO.ACTION.error = 'cant_work' return false end ECO.ACTION = Config.workstations[zoneId]; ECO.ACTION.id = zoneId return true end -- ITEM CHECK function getItem(itemName) local item = eCore:getRegisteredItem(itemName:lower()); if item then return { label = item.label, image = item.image or item.name .. '.png' } end return false end function setWorkstationAccess(playerData, playerAcePermissions) for _, v in pairs(Config.workstations) do local perm = accessManagement(v, playerData, playerAcePermissions) v.accessToUse = perm.accessToUse v.accessToRemove = perm.accessToRemove end end function inZoneId() if loaded then local coords = GetEntityCoords(PlayerPedId()) for id, workstation in pairs(Config.workstations) do if #(coords - workstation.pos.xyz) < workstation.actionDistance then return id end end end return false end function locationAnalysis(pos) local result = true local reason = '' for _, v in pairs(Config.workstations) do if #(pos - v.pos.xyz) < 2.5 then return false, 'another_workstation_is_too_close' end end for i = 1, #Config.restrictedArea do if #(Config.restrictedArea[i].center - pos) < Config.restrictedArea[i].radius then return false, 'in_a_restricted_area' end end if IsPointOnRoad(pos.x, pos.y, pos.z) then return false, 'in_a_restricted_area' end return result, reason end function updatePlayerAcePermissions(src) local temp = {} for perm in pairs(Config.usedAcePermissions) do temp[perm] = IsPlayerAceAllowed(src, perm) end return temp end function getIngredientsToRemove(recipe) local temp = {} for _, ingredient in pairs(recipe.ingredients) do if ingredient.remove then table.insert(temp, ingredient) end end return temp end ---Based on a recipe, it calculates how many objects can be made from the materials in the inventory ---@param playerData table ---@param recipe { ingredients: table, params: {amount: number, remove: boolean}} ---@return number function maxProduct(playerData, recipe) local max = -1; local inventoryAmount, result local ingredients = recipe.ingredients; local inventory = eCore:getAmountOfItems(eCore:getInventory(playerData)) cLog('functions.lua -> maxProduct:inventory', inventory, 4) cLog('functions.lua -> maxProduct:recipe', recipe, 4) for _, ingredient in pairs(ingredients) do inventoryAmount = inventory[ingredient.name] cLog('functions.lua -> maxProduct:for ingredients', ingredient, 4) if(not ingredient or not ingredient.name or not ingredient.amount) then ingredient = ingredient or {} local errorMessage = ("Missing ingredient data: recipe: %s, ingredient name: %s, amount: %s"):format( tostring(recipe.name), tostring(ingredient.name), tostring(ingredient.amount) ) eCore:sendMessage(errorMessage, "error") print(("^1 %s ^7"):format(errorMessage)) return 0 end if (inventoryAmount and inventoryAmount < ingredient.amount) then max = 0 break end if ingredient.remove then result = math.floor(inventoryAmount / ingredient.amount); max = (max == -1) and result or math.min(max, result) end end return max end function blueprintKnowledgeCheck(recipe, knowledge) if not recipe.blueprints then return true end if not knowledge or type(knowledge.blueprints) ~= 'table' then return false, 'no_metadata_available' end for _, blueprint in pairs(recipe.blueprints) do if not hf.inTable(blueprint.knowledge, knowledge.blueprints) then return false, 'not_enough_knowledge' end end return true end --- Adds the item to the inventory taking into account the chances and uniqueness of the item --- If an item is unique or a weapon, add it one at a time function createInventoryItem() local self = {} local failed, done = 0, 0 local idx = eCoreConfig.fields --- @param params table --- @field xPlayer table --- @field item string --- @field amount number --- @field isUnique boolean --- @field isWeapon boolean --- @field chance number --- @field metadata number item metadata e.g: serial number --- @return boolean, table success, {reason, failed, done} function self.add(params) failed, done = 0, 0 if params.isWeapon or params.isUnique then for i = 1, params.amount do local success, reason = self.addItem(params, 1) if not success then return false, { reason = reason, failed = failed, done = done } end end else local success, reason = self.addItem(params, params.amount) if not success then return false, { reason = reason, failed = failed, done = done } end end return true, { reason = '', failed = failed, done = done } end function self.addItem(params, count) local metadata = hf.isPopulatedTable(params.metadata) and table.clone(params.metadata) or {} local fail = false if type(params.chance) == 'number' and params.chance < 100 then fail = not hf.draw(params.chance) end if fail then failed = failed + 1 params = nil else if params.isWeapon then metadata[idx.serial] = metadata[idx.serial] or hf.getSerialNumber() end local success, reason = eCore:addItem( params.xPlayer, params.item, count, nil, metadata) cLog('addProduct -> createInventoryItem:addItem', { success = success, reason = reason }, 4) if not success then return false, reason end done = done + count end return true end return self end function addKnowledge(playerId, knowledge) if not Config.systemMode.blueprint then return false, 'blueprint_system_not_active' end local meta = exports.e_core:getMeta(playerId, 'knowledge') if not meta or type(meta.blueprints) ~= 'table' then return false, 'no_metadata_available' end if hf.inTable(knowledge, meta.blueprints) then return false, 'you_already_know_that' end table.insert(meta.blueprints, knowledge) return exports.e_core:setMeta(playerId, 'knowledge', meta) end