Files
wnsrc/gamemodes/darkrp/plugins/willardskills/libs/sh_recipe.lua

377 lines
10 KiB
Lua
Raw Normal View History

2024-08-04 22:55:00 +03:00
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local ix = ix
ix.recipe = ix.recipe or {}
ix.recipe.stored = ix.recipe.stored or {}
--[[
Begin defining the recipe class base for other recipe's to inherit from.
--]]
--[[ Set the __index meta function of the class. --]]
local CLASS_TABLE = {__index = CLASS_TABLE}
CLASS_TABLE.name = "Blueprint Base"
CLASS_TABLE.uniqueID = "blueprint_base"
CLASS_TABLE.skin = 0
CLASS_TABLE.model = "models/error.mdl"
CLASS_TABLE.category = "Other"
CLASS_TABLE.description = "A recipe with no description."
-- Called when the recipe is converted to a string.
function CLASS_TABLE:__tostring()
return "RECIPE["..self.name.."]"
end
--[[
A function to override an recipe's base data. This is
just a nicer way to set a value to go along with
the method of querying.
--]]
function CLASS_TABLE:Override(varName, value)
self[varName] = value
end
-- A function to register a new recipe.
function CLASS_TABLE:Register()
return ix.recipe:Register(self)
end
function CLASS_TABLE:PlayerCanCraftRecipe(client)
return ix.recipe:PlayerCanCraftRecipe(self, client)
end
--[[
End defining the base recipe class.
Begin defining the recipe utility functions.
--]]
-- A function to get all recipes.
function ix.recipe:GetAll()
return self.stored
end
-- A function to get a new recipe.
function ix.recipe:New()
local object = {}
setmetatable(object, CLASS_TABLE)
CLASS_TABLE.__index = CLASS_TABLE
return object
end
-- A function to register a new recipe.
function ix.recipe:Register(recipe)
recipe.uniqueID = string.utf8lower(string.gsub(recipe.uniqueID or string.gsub(recipe.name, "%s", "_"), "['%.]", ""))
self.stored[recipe.uniqueID] = recipe
if (recipe.model) then
util.PrecacheModel(recipe.model)
if (SERVER) then
resource.AddFile(recipe.model)
end
end
end
-- A function to get an recipe by its name.
function ix.recipe:FindByID(identifier)
if (identifier and identifier != 0 and type(identifier) != "boolean") then
if (self.stored[identifier]) then
return self.stored[identifier]
end
local lowerName = string.utf8lower(identifier)
local recipe = nil
for _, v in pairs(self.stored) do
local recipeName = v.name
if (string.find(string.utf8lower(recipeName), lowerName)
and (!recipe or string.utf8len(recipeName) < string.utf8len(recipe.name))) then
recipe = v
end
end
return recipe
end
end
function ix.recipe:Initialize()
local recipes = self:GetAll()
for _, v in pairs(recipes) do
if (v.OnSetup) then
v:OnSetup()
end
end
end
-- Called when a player attempts to craft an item.
function ix.recipe:PlayerCanCraftRecipe(recipe, client, inventory)
local character = client:GetCharacter()
inventory = inventory or character:GetInventory()
if (recipe.skill != "bartering" and !character:CanDoAction("recipe_"..recipe.uniqueID)) then
return false, "Vous n'avez pas le niveau requis pour craft cela."
end
-- Check if the player has all the needed tools if there are any needed
if (recipe.tool and !istable(recipe.tool)) then
if !ix.item.list[recipe.tool] then
ErrorNoHalt("[Crafting] La recette "..recipe.name.." outil inexistant "..recipe.tool.."!\n")
return false, "Recipe has unexisting tool "..recipe.tool.."!"
elseif (!inventory:HasItem(recipe.tool)) then
return false, "Vous n'avez pas : "..ix.item.list[recipe.tool].name.."."
end
end
if recipe.tools and istable(recipe.tools) then
for _, v in pairs(recipe.tools) do
if ix.item.list[v] then
if (!inventory:HasItem(v)) then
return false, "Vous n'avez pas : "..ix.item.list[v].name.."."
end
else
ErrorNoHalt("[Crafting] Recipe "..recipe.name.." has an unexisting tool "..v.."!\n")
return false, "Recipe has unexisting tool "..v.."!"
end
end
end
-- Check for the ingredients
if (recipe.ingredients) then
for ingredient, amount in pairs(recipe.ingredients) do
if (!ix.item.list[ingredient]) then
ErrorNoHalt("[Crafting] Recipe "..recipe.name.." has an unexisting ingredient "..ingredient.."!\n")
return false, "Recipe has unexisting ingredient "..ingredient.."!"
end
local count = inventory:GetItemCount(ingredient)
if (count == 0) then
return false, "You do not have any "..ix.item.list[ingredient].name.."."
elseif (count < amount) then
local name = ingredient
if (amount > 1) then
name = Schema:Pluralize(ix.item.list[ingredient].name)
end
return false, "You need at least "..tostring(amount).." "..name.."."
end
end
end
-- Check if player is near a crafting station if needed
if (recipe.station) then
if (!istable(recipe.station)) then
if (ix.item.list[recipe.station]) then
-- Find the entity the player is looking at
local entity = client:GetEyeTraceNoCursor().Entity
if (IsValid(entity)) then
if (entity:GetClass() != "ix_item") then
return false, "L'établi est invalide !"
else
if !entity.GetItemTable or (entity.GetItemTable and !entity:GetItemTable()) then
return false, "Ce n'est pas le bon établi !"
end
local itemTable = entity:GetItemTable()
if (itemTable.uniqueID != recipe.station) then
return false, "C'est n'est pas le bon établi pour ce craft !"
end
if (client:GetShootPos():DistToSqr(entity:GetPos()) > 100 * 100) then
return false, "Vous devez vous rapprocher de l'établi !"
end
end
else
return false, "Vous devez regardez un établi !"
end
else
ErrorNoHalt("[Crafting] Recipe "..recipe.name.." has an unexisting station "..recipe.station.."!\n")
return false, "Recipe has unexisting station "..recipe.station.."!"
end
else
local validStations = {}
local bFound, bInvalidStationEntity = false, false
local entity = client:GetEyeTraceNoCursor().Entity
local bEntityValid = IsValid(entity)
if (!bEntityValid or client:GetShootPos():DistToSqr(entity:GetPos()) > 100 * 100) then
bInvalidStationEntity = true
end
local campFire = recipe.canUseCampfire
local campFireText = campFire and " or a Campfire" or ""
if (campFire and !bInvalidStationEntity and bEntityValid and entity:GetClass() == "ix_campfire") then
bFound = true
end
if (!bFound) then
if (entity:GetClass() != "ix_item" or !entity:GetItemTable()) then
bInvalidStationEntity = true
end
for _, v in pairs(recipe.station) do
if ix.item.list[v] then
validStations[#validStations + 1] = ix.item.list[v]:GetName()
if (bInvalidStationEntity) then continue end -- too far/invalid/wrong class, don't bother checking
local itemTable = entity:GetItemTable()
if (itemTable.uniqueID != v) then
continue
end
bFound = true
break -- valid station found, stop checking station loop
end
end
end
if (!bFound) then
return false, string.format("You need to be near and looking at a %s"..campFireText..".", table.concat(validStations, " or a "))
end
end
end
-- Check if player has the crafting license if needed
if (recipe.skill == "bartering" and !character:HasPermit(recipe.category)) then
return false, "You do not have a business permit for this category of items, contact the Combine Civil Administration."
end
if (recipe.cost and isnumber(recipe.cost)) then
local itemID = character:GetIdCard()
if (itemID) then
if (ix.item.instances[itemID]) then
local credits = ix.item.instances[itemID]:GetCredits()
if (credits < recipe.cost) then
return false, "You do not have enough credits to purchase this item!"
end
else
return false, "Could not find ID card!"
end
else
return false, "You do not have an active ID card!"
end
end
return true
end
if (CLIENT) then
function ix.recipe:GetIconInfo(recipe)
local model = recipe.model or "models/error.mdl"
local skin = recipe.skin
return model, skin
end
function ix.recipe:CanPlayerSeeRecipe(recipe)
if (recipe.hidden) then
return false
end
return true
end
else
function ix.recipe:PlayerCraftRecipe(recipe, client)
if (recipe.PlayerCraftRecipe) then
recipe:PlayerCraftRecipe(client)
return
end
local character = client:GetCharacter()
local inventory = character:GetInventory()
-- Take all the ingredients
for ingredient, amount in pairs(recipe.ingredients) do
for _ = 1, amount do
local item = inventory:HasItem(ingredient)
if (item) then
item:Remove()
else
break
end
end
end
-- Break tools
if (recipe.tools and !table.IsEmpty(recipe.tools)) then
for k, v in pairs(recipe.tools) do
local item = inventory:HasItem(v)
if (item and item.isTool) then
item:DamageDurability(1)
end
end
end
if (recipe.tool) then
local item = inventory:HasItem(recipe.tool)
if (item and item.isTool) then
item:DamageDurability(1)
end
end
-- Give the result
for result, amount in pairs(recipe.result) do
local item = ix.item.list[result]
if (!item) then continue end
local actualAmount
if (type(amount) == "table") then
actualAmount = amount[math.random(1, #amount)]
else
actualAmount = amount
end
if (item.maxStackSize) then
-- fill up existing stacks if possible
local items = inventory:GetItemsByUniqueID(result)
for _, v in ipairs(items) do
if (v:GetStackSize() < v.maxStackSize) then
local toAdd = math.min(v.maxStackSize - v:GetStackSize(), actualAmount)
actualAmount = actualAmount - toAdd
v:AddStack(toAdd)
if (actualAmount == 0) then
break
end
end
end
end
if (actualAmount > 0) then
for i = 1, actualAmount, (item.maxStackSize or 1) do
-- Give new items in stacks if possible
local data
if (item.maxStackSize) then
data = {stack = math.min(actualAmount + 1 - i, item.maxStackSize)}
end
if (!inventory:Add(result, 1, data)) then
ix.item.Spawn(result, client, nil, nil, data)
end
end
end
end
-- Set the player's next crafting time
client.ixNextCraftTime = CurTime() + 2
netstream.Start("CraftTime", client.ixNextCraftTime)
character:DoAction("recipe_"..recipe.uniqueID)
end
end