Sistema de comida y restaurantes para FiveM: gestión de cocinas
Gestiona restaurantes en FiveM con recetas, cajas registradoras, trabajos de reparto y scripts de comida para dar vida a tu ciudad.
Agency Scripts
Fundador y desarrollador principal en Agency Scripts
Por qué los sistemas de restaurantes mejoran el roleplay
Los sistemas de comida y restaurantes son algunas de las funciones más sociales que puedes añadir a un servidor de roleplay de FiveM. A diferencia de actividades en solitario como la minería o la pesca, los restaurantes crean puntos de encuentro espontáneos donde los jugadores cocinan, sirven y comen juntos. Un sistema de restaurantes bien diseñado ofrece a los jugadores civiles un trabajo significativo que no implica delitos, da a los personajes un motivo para visitar lugares con regularidad e introduce una vía para retirar dinero de la economía mediante la compra de ingredientes. Los restaurantes también crean cadenas de suministro cuando se combinan con scripts de agricultura o caza: un jugador cultiva tomates, otro los entrega y un tercero los cocina para preparar una hamburguesa. Este ciclo de juego interconectado es lo que distingue a un servidor vivo de uno en el que los jugadores se limitan a repetir la misma ruta una y otra vez. Los alimentos pueden proporcionar mejoras temporales a la salud, la resistencia o la regeneración de armadura, lo que hace que los restaurantes sean relevantes para todos los jugadores del servidor, independientemente de su trabajo o facción.
Configuración del restaurante y diseño del menú
Empieza por definir las ubicaciones de tus restaurantes, sus menús y los ingredientes necesarios para cada plato. Una configuración basada en datos permite a los propietarios de servidores añadir restaurantes sin modificar la lógica principal. Cada restaurante debería tener una identidad propia gracias a su menú, los elementos decorativos del interior y los uniformes del personal NPC. Estructura la configuración para que cada elemento del menú indique sus ingredientes necesarios, el tiempo de preparación, el precio de venta y cualquier efecto de mejora que proporcione a quien lo consuma. Así, para ajustar el equilibrio de la economía de comida bastará con cambiar los valores de configuración en lugar de reescribir el código:
Config.Restaurants = {
['burgershot'] = {
label = 'Burger Shot',
blip = { sprite = 106, color = 1, scale = 0.8 },
zones = {
counter = vector3(-1196.42, -894.04, 13.98),
kitchen = vector3(-1199.71, -897.12, 13.98),
storage = vector3(-1202.84, -899.35, 13.98),
},
menu = {
{
item = 'bleeder_burger',
label = 'Bleeder Burger',
price = 25,
ingredients = {
{ item = 'raw_patty', amount = 2 },
{ item = 'burger_bun', amount = 1 },
{ item = 'lettuce', amount = 1 },
{ item = 'cheese_slice', amount = 2 },
},
craftTime = 8000,
buffs = {
hunger = 45,
thirst = 5,
armor_regen = { amount = 2, duration = 120 }
}
},
{
item = 'heartstopper',
label = 'Heart Stopper',
price = 40,
ingredients = {
{ item = 'raw_patty', amount = 3 },
{ item = 'burger_bun', amount = 1 },
{ item = 'bacon', amount = 4 },
{ item = 'cheese_slice', amount = 3 },
{ item = 'onion_ring', amount = 2 },
},
craftTime = 12000,
buffs = {
hunger = 80,
thirst = -10,
stamina_boost = { amount = 15, duration = 180 }
}
},
},
requiredJob = 'burgershot',
},
}
El zones la tabla divide el restaurante en áreas funcionales. La zona del mostrador es donde los clientes hacen sus pedidos y reciben la comida. La zona de cocina está restringida a los empleados, que la usan para cocinar. La zona de almacenamiento es donde se guardan y gestionan los ingredientes. Esta separación espacial obliga a seguir un flujo de trabajo realista en el que un cocinero no puede atender a los clientes directamente desde los fogones, lo que fomenta el trabajo en equipo entre el personal de sala y el de cocina.
Mecánicas de cocina y flujo de fabricación
El proceso de cocina debería ser interactivo sin resultar tedioso. Cuando un jugador empiece a preparar un plato, comprueba que todos los ingredientes necesarios estén en el inventario de almacenamiento del restaurante, réstalos y comienza una barra de progreso o una secuencia de minijuego. Las barras de progreso simples funcionan para los platos básicos, pero añadir minijuegos de pruebas de habilidad para los platos prémium crea una sensación de dominio y evita los abusos de cocina AFK. La animación de cocina debería usar los natives adecuados de GTA, como los escenarios de barbacoa o de encimera de cocina, para mostrar visualmente a los observadores cercanos lo que está haciendo el jugador:
function StartCooking(restaurantId, menuIndex)
local restaurant = Config.Restaurants[restaurantId]
local recipe = restaurant.menu[menuIndex]
-- Check ingredients in storage
local hasAll = lib.callback.await('restaurant:checkIngredients', false,
restaurantId, recipe.ingredients)
if not hasAll then
lib.notify({ description = 'Missing ingredients!', type = 'error' })
return
end
-- Lock player into cooking animation
local playerPed = PlayerPedId()
local animDict = 'mini@repair'
lib.requestAnimDict(animDict)
TaskPlayAnim(playerPed, animDict, 'fixing_a_player', 8.0, -8.0,
-1, 1, 0, false, false, false)
-- Cooking progress with skill check
local success = lib.skillCheck(
{'easy', 'easy', 'medium'},
{'w', 'a', 's', 'd'}
)
ClearPedTasks(playerPed)
if success then
TriggerServerEvent('restaurant:finishCooking', restaurantId, menuIndex)
lib.notify({ description = 'Cooked: ' .. recipe.label, type = 'success' })
else
-- Failed cooking wastes some ingredients
TriggerServerEvent('restaurant:failedCooking', restaurantId, menuIndex)
lib.notify({ description = 'Burnt the food! Some ingredients wasted.',
type = 'error' })
end
end
La mecánica de pruebas de habilidad añade un elemento de riesgo y recompensa a la cocina. Los intentos fallidos deberían desperdiciar una parte de los ingredientes, no todos, para que los jugadores nuevos no reciban un castigo excesivo y, a la vez, se incentive la mejora de sus habilidades. Puedes ajustar la dificultad según el valor del plato, de modo que los artículos baratos sean fáciles de cocinar y los platos exclusivos más caros exijan verdadera atención. Así se crea una progresión natural en la que los nuevos empleados empiezan con platos sencillos y avanzan hasta el menú prémium.
Cadena de suministro de ingredientes
Los restaurantes necesitan un flujo constante de ingredientes y la forma en que los jugadores los obtienen define una parte importante del ciclo de juego. Hay tres enfoques habituales: comprar a proveedores NPC mayoristas, abastecerse de granjas gestionadas por jugadores o mediante la caza, y usar un modelo híbrido. El enfoque mayorista es más sencillo de implementar y garantiza la disponibilidad, pero no fomenta la interacción entre jugadores. Abastecerse de otros jugadores crea relaciones económicas interesantes, pero puede dejar el restaurante sin actividad cuando los proveedores están desconectados. El modelo híbrido es el que mejor funciona: los ingredientes básicos, como los panecillos, el aceite y los condimentos, se consiguen de NPC, mientras que los ingredientes prémium, como la carne fresca, las verduras orgánicas y las salsas especiales, deben obtenerse mediante actividades de los jugadores. Esto garantiza que los restaurantes siempre puedan funcionar a un nivel básico y, a la vez, recompensa el funcionamiento de toda la cadena de suministro cuando todas sus partes se conectan. Implementa un sistema de almacenamiento para cada restaurante que registre las cantidades de ingredientes y permita a los encargados hacer pedidos al por mayor, cuyo coste se descontará de la cuenta bancaria del restaurante:
RegisterNetEvent('restaurant:orderSupplies', function(restaurantId, order)
local src = source
local Player = QBCore.Functions.GetPlayer(src)
-- Verify player is manager rank
if Player.PlayerData.job.name ~= restaurantId then return end
if Player.PlayerData.job.grade.level < 3 then
TriggerClientEvent('QBCore:Notify', src,
'Only managers can order supplies', 'error')
return
end
-- Calculate total cost
local totalCost = 0
for _, item in ipairs(order) do
local wholesalePrice = Config.WholesalePrices[item.name]
if wholesalePrice then
totalCost = totalCost + (wholesalePrice * item.amount)
end
end
-- Deduct from restaurant bank account
local balance = exports['qb-management']:GetAccount(restaurantId)
if balance < totalCost then
TriggerClientEvent('QBCore:Notify', src,
'Insufficient restaurant funds', 'error')
return
end
exports['qb-management']:RemoveMoney(restaurantId, totalCost)
-- Add items to restaurant storage
for _, item in ipairs(order) do
AddToRestaurantStorage(restaurantId, item.name, item.amount)
end
TriggerClientEvent('QBCore:Notify', src,
string.format('Order placed! $%d deducted', totalCost), 'success')
end)
Flujo de pedidos y servicio al cliente
La experiencia del cliente debe ser fluida, tanto si hace el pedido a un cajero NPC como a un empleado jugador. Cuando un cliente se acerque a la zona del mostrador, muestra una interfaz de menú con los artículos disponibles, sus precios y las descripciones de los potenciadores activos. En los restaurantes atendidos por jugadores, el pedido debe enviarse a la pantalla de cocina para que los cocineros vean los pedidos entrantes en tiempo real. Implementa un sistema de cola que siga cada pedido desde que se realiza hasta que se prepara y se entrega. Así se crea una simulación de comida rápida en la que se acumulan pedidos en la cocina durante las horas punta, lo que añade una presión auténtica al rol de cocinero. Muestra el estado del pedido a los clientes con indicadores sencillos: pedido realizado, en preparación, listo para recoger. Cuando la comida esté lista, avisa al cliente para que la recoja en el mostrador. Para ofrecer una experiencia prémium, permite que los camareros jugadores entreguen la comida directamente a los clientes sentados en las mesas y reciban propinas según la rapidez del servicio.
Potenciadores de comida y efectos de consumo
Los alimentos deben ofrecer ventajas de juego significativas, no limitarse a restaurar el hambre. Implementa un sistema de potenciadores en el que distintos alimentos otorguen modificaciones temporales de estadísticas para animar a los jugadores a comer estratégicamente antes de realizar actividades. Una comida que aumente la resistencia antes de una persecución a pie, un plato que regenere el blindaje antes de un atraco o una comida que recupere salud con el tiempo después de una pelea hacen que los alimentos sean realmente valiosos para la economía del servidor. Registra los potenciadores activos de cada jugador y muéstralos en el HUD para que los jugadores sepan qué efectos tienen activos y cuándo caducan:
local activeBuffs = {}
function ApplyFoodBuff(buffType, amount, duration)
-- Remove existing buff of same type
if activeBuffs[buffType] then
activeBuffs[buffType].active = false
end
activeBuffs[buffType] = {
amount = amount,
endTime = GetGameTimer() + (duration * 1000),
active = true
}
-- Send buff data to HUD
SendNUIMessage({
action = 'addBuff',
buffType = buffType,
amount = amount,
duration = duration
})
-- Create buff application thread
CreateThread(function()
local buff = activeBuffs[buffType]
while buff.active and GetGameTimer() < buff.endTime do
if buffType == 'armor_regen' then
local current = GetPedArmour(PlayerPedId())
if current < 100 then
SetPedArmour(PlayerPedId(), math.min(100, current + amount))
end
elseif buffType == 'stamina_boost' then
RestorePlayerStamina(PlayerId(), amount * 0.1)
elseif buffType == 'health_regen' then
local current = GetEntityHealth(PlayerPedId())
local max = GetEntityMaxHealth(PlayerPedId())
if current < max then
SetEntityHealth(PlayerPedId(), math.min(max, current + amount))
end
end
Wait(1000)
end
activeBuffs[buffType] = nil
SendNUIMessage({ action = 'removeBuff', buffType = buffType })
end)
end
Equilibra cuidadosamente los potenciadores de comida para que mejoren la experiencia de juego sin volverse obligatorios. Deben ofrecer una ventaja perceptible, pero no ser tan potentes que los jugadores sientan que tienen que comer antes de cada actividad. Mantén una duración moderada, entre dos y cinco minutos, para que la economía de potenciadores siga activa. Considera añadir rendimientos decrecientes si se consume el mismo alimento varias veces en poco tiempo para evitar abusos por acumulación de potenciadores.
Gestión de empleados y nóminas
Un sistema de restaurante necesita una jerarquía bien definida, con distintos roles y permisos. Define al menos tres niveles: trabajador, supervisor y gerente. Los trabajadores pueden cocinar platos y atender a los clientes. Los supervisores pueden hacer todo lo que hacen los trabajadores, además de gestionar el almacén de ingredientes y aprobar pedidos. Los gerentes tienen el control total, incluida la contratación y el despido de empleados, la fijación de precios y el acceso a la cuenta bancaria del restaurante. Vincula las nóminas a los ingresos del restaurante para que los empleados reciban un salario base más una comisión por los artículos que cocinen o sirvan personalmente. Así se incentiva la participación activa en lugar de fichar y quedarse AFK. Registra estadísticas individuales de cada empleado, como los artículos cocinados, los clientes atendidos y los ingresos generados, para crear clasificaciones y evaluaciones de rendimiento que aporten profundidad a la experiencia laboral.
Optimización del rendimiento
Los sistemas de restaurante incluyen varias zonas de interacción, NPC, objetos de utilería y seguimiento de pedidos en tiempo real, que pueden afectar al rendimiento del cliente si no se optimizan cuidadosamente. Usa interacciones del sistema de selección de objetivos en lugar de comprobaciones de distancia basadas en marcadores para eliminar los cálculos de coordenadas en cada fotograma. Renderiza los objetos de utilería del interior del restaurante solo cuando haya jugadores dentro del edificio, usando IsPlayerInScope comprobaciones. Agrupa los mensajes de NUI para mostrar la cola de pedidos en lugar de enviar actualizaciones individuales cada vez que cambie un pedido. En el servidor, guarda en caché las existencias del almacén del restaurante en memoria y escríbelas en la base de datos en intervalos programados, en vez de hacerlo tras cada cambio de ingredientes. Cuando haya varios restaurantes activos al mismo tiempo, escalona sus ciclos de sincronización con la base de datos para evitar picos de escritura. Limpia todos los blips, objetos de utilería y entidades NPC cuando se detenga el recurso para evitar entidades huérfanas que se acumulen tras reiniciar recursos. Prueba el sistema con varios restaurantes en funcionamiento, varios cocineros trabajando al mismo tiempo y un flujo constante de pedidos para detectar cuellos de botella antes de que los encuentren tus jugadores.