Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local img = [[
- ██╗██╗ ██╗ █████╗ ██████╗ ██████╗ ██╗ ██╗
- ██╔╝██║ ██║██╔══██╗██╔══██╗██╔══██╗ ██║ ██║
- ██╔╝ ██║ █╗ ██║███████║██████╔╝██████╔╝ ██║ █╗ ██║
- ██╔╝ ██║███╗██║██╔══██║██╔══██╗██╔═══╝ ██║███╗██║
- ██╔╝ ╚███╔███╔╝██║ ██║██║ ██║██║ ╚███╔███╔╝
- ╚═╝ ╚══╝╚══╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚══╝╚══╝
- ]]
- local ore_dict = {
- {
- "Железная руда",
- "Железный слиток",
- take = {name = "minecraft:iron_ore", damage = 0},
- give = {name = "minecraft:iron_ingot", damage = 0},
- rate = {take = 4, give = 9}
- },
- {
- "Золотая руда",
- "Золотой слиток",
- take = {name = "minecraft:gold_ore", damage = 0},
- give = {name = "minecraft:gold_ingot", damage = 0},
- rate = {take = 4, give = 9}
- },
- {
- "Медная руда",
- "Медный слиток",
- take = {name = "IC2:blockOreCopper", damage = 0},
- give = {name = "IC2:itemIngot", damage = 0},
- rate = {take = 4, give = 9}
- },
- {
- "Оловянная руда",
- "Оловянный слиток",
- take = {name = "IC2:blockOreTin", damage = 0},
- give = {name = "IC2:itemIngot", damage = 1},
- rate = {take = 4, give = 9}
- },
- {
- "Свинцовая руда",
- "Свинцовый слиток",
- take = {name = "IC2:blockOreLead", damage = 0},
- give = {name = "IC2:itemIngot", damage = 5},
- rate = {take = 4, give = 8}
- },
- {
- "Никелевая руда",
- "Никелевый слиток",
- take = {name = "ThermalFoundation:Ore", damage = 4},
- give = {name = "ThermalFoundation:material", damage = 68},
- rate = {take = 1, give = 2}
- },
- {
- "Серебряная руда",
- "Серебряный слиток",
- take = {name = "ThermalFoundation:Ore", damage = 2},
- give = {name = "IC2:itemIngot", damage = 6},
- rate = {take = 4, give = 9}
- },
- }
- local unicode = require("unicode")
- local computer = require("computer")
- local com = require("component")
- local event = require("event")
- local internet = com.internet -- Добавляем интернет компонент
- local gpu = com.gpu
- local me = com.me_interface -- Добавляем ME интерфейс
- local pim = com.pim -- Добавляем PIM (Player Interface)
- local w, h = gpu.maxResolution()
- local defBG, defFG = gpu.getBackground(), gpu.getForeground()
- gpu.setResolution(w, h)
- -- Кэширование данных
- local cached = {
- lastUpdate = 0,
- updateInterval = 5,
- oreQuantities = {}
- }
- -- Статистика обменов
- local stats = {
- exchanges = 0,
- totalOre = 0,
- totalIngots = 0
- }
- -- Буфер экрана
- local screenBuffer = {}
- -- Цветовые схемы
- local colors = {
- info = 0x00ff00,
- warning = 0xffff00,
- error = 0xff0000,
- border = 0x64fff2,
- title = 0x00a400,
- subtitle = 0xFFFFFF,
- powered = 0x64fff2,
- bg = 0x101010
- }
- -- Анимация появления логотипа
- local function animateLogo(img, x, y, fore, delay, fast)
- fore = fore or colors.title
- local i = 0
- local sleepTime = fast and 0.01 or (delay or 0.07)
- for line in img:gmatch("([^\n]*)\n?") do
- gpu.setForeground(fore)
- gpu.set(x, y + i, line)
- os.sleep(sleepTime)
- i = i + 1
- end
- end
- -- Центрирование текста (перемещено выше)
- local function center(height, text, color)
- gpu.setForeground(color)
- local textLen = unicode.len(text)
- local x = math.max(1, math.floor(w / 2 - textLen / 2))
- gpu.set(x, height, text)
- end
- -- Красивое приветствие
- local greetings = {
- "Добро пожаловать в обменник!",
- "Удачного обмена!",
- "Пусть удача сопутствует вам!",
- "Меняю руду на слитки — быстро и честно!",
- "Powered by DemonAve"
- }
- local function showGreeting(player)
- local greet = greetings[math.random(1, #greetings)]
- if player then
- center(h - 14, greet .. " | " .. player, colors.subtitle)
- else
- center(h - 14, greet, colors.subtitle)
- end
- end
- local antiSpam = {
- lastAction = 0,
- cooldown = 1
- }
- -- Таймер обновления данных
- local function shouldUpdate()
- local currentTime = computer.uptime()
- if currentTime - (cached.lastUpdate or 0) > (cached.updateInterval or 5) then
- cached.lastUpdate = currentTime
- return true
- end
- return false
- end
- -- Локальный вывод
- local function log(message, level, player)
- local levels = {
- info = 0x00ff00,
- warning = 0xffff00,
- error = 0xff0000
- }
- gpu.fill(1, h - 13, w, 1, " ") -- очищаем строку
- center(h - 13, message, colors[level] or colors.subtitle)
- end
- local function canProcess()
- local current = computer.uptime()
- if current - antiSpam.lastAction < antiSpam.cooldown then
- return false
- end
- antiSpam.lastAction = current
- return true
- end
- local function bufferSet(x, y, text, fore, back)
- local key = string.format("%d:%d", x, y)
- local current = screenBuffer[key]
- if not current or current.text ~= text or current.fore ~= fore or current.back ~= back then
- screenBuffer[key] = {text = text, fore = fore, back = back}
- gpu.setForeground(fore)
- gpu.setBackground(back)
- gpu.set(x, y, text)
- end
- end
- local function populateQty()
- local totalOre = 0
- for i, ore in pairs(ore_dict) do
- local fingerprint = {id = ore.give.name, dmg = ore.give.damage}
- local ok, item = pcall(me.getItemDetail, fingerprint)
- if not ok or item == nil then
- ore.qty = 0
- ore.sizeOfStack = 64
- else
- local basicOk, basicItem = pcall(function() return item.basic() end)
- if not basicOk or not basicItem then
- ore.qty = 0
- ore.sizeOfStack = 64
- else
- ore.sizeOfStack = basicItem.max_size
- ore.qty = basicItem.qty
- totalOre = totalOre + basicItem.qty
- end
- end
- end
- return totalOre
- end
- local function displayOres()
- local line = 3
- local colOre = math.floor(w * 0.04)
- local colIngot = math.floor(w * 0.48)
- local colTake = math.floor(w * 0.32)
- local colGive = colTake + 8
- local colArrow = colTake + 4
- local colQty = math.floor(w * 0.88)
- local colAvail = math.floor(w * 0.75)
- -- Верхняя рамка
- gpu.setForeground(colors.border)
- gpu.set(1, line - 1, "╔" .. string.rep("═", w - 2) .. "╗")
- gpu.set(1, 3,"║")
- gpu.set(1, 4,"║")
- gpu.set(gpu.getResolution(), 3,"║")
- gpu.set(gpu.getResolution(), 4,"║")
- -- Заголовки таблицы (увеличенный текст)
- gpu.setForeground(colors.title)
- gpu.set(colOre + 2, line, "РУДА")
- gpu.set(colTake + 2, line, "КУРС")
- gpu.set(colIngot + 4, line, "СЛИТОК")
- gpu.set(colAvail + 19, line, "ДОСТУПНО")
- -- Вторая строка под заголовком можно использовать для подзаголовков или оставить пустой
- gpu.set(colOre, line + 1, "")
- gpu.set(colTake + 1, line + 1, "")
- gpu.set(colIngot, line + 1, "")
- gpu.set(colAvail, line + 1, "")
- -- Разделитель под заголовком
- gpu.setForeground(colors.border)
- gpu.set(1, line + 2, "╠" .. string.rep("─", w - 2) .. "╣")
- local row = line + 3
- for i, ore in ipairs(ore_dict) do
- gpu.setForeground(colors.info)
- gpu.set(colOre, row, ore[1] or "?")
- gpu.set(colIngot, row, ore[2] or "?")
- gpu.setForeground(0xFF00FF)
- gpu.set(colTake, row, tostring((ore.rate and ore.rate.take) or "?"))
- gpu.set(colGive, row, tostring((ore.rate and ore.rate.give) or "?"))
- gpu.setForeground(colors.warning)
- gpu.set(colArrow, row, "→")
- gpu.setForeground(colors.info)
- gpu.set(colQty, row, tostring(ore.qty or 0))
- -- Боковые границы
- gpu.setForeground(colors.border)
- gpu.set(1, row, "║")
- gpu.set(w, row, "║")
- -- Полоса под каждой строкой, кроме последней
- if i < #ore_dict then
- gpu.setForeground(colors.border)
- gpu.set(1, row + 1, "╟" .. string.rep("─", w - 2) .. "╢")
- row = row + 2
- else
- row = row + 1
- end
- end
- -- Нижняя рамка
- gpu.setForeground(colors.border)
- gpu.set(1, row, "╚" .. string.rep("═", w - 2) .. "╝")
- end
- local function updateOres()
- local totalOre = populateQty()
- gpu.fill(1, 1, w, h - 16, " ")
- if totalOre == 0 then
- gpu.fill(1, 1, w, h - 15, " ")
- center(h - 15, "Нет соединения с МЭ", 0xff0000)
- else
- displayOres()
- end
- end
- local function giveItemFromMe(item, dmg, amount)
- local fingerprint = {id = item, dmg = dmg}
- local ok, res = pcall(me.exportItem, fingerprint, "UP", amount)
- if ok and res and res.size then
- return res.size
- else
- return 0
- end
- end
- local function giveIngot(toGive, ore)
- local totalGive = 0
- local givePreIteration = 0
- while totalGive < toGive do
- if toGive - totalGive > 64 then
- givePreIteration = ore.sizeOfStack
- else
- givePreIteration = toGive - totalGive
- end
- local gived = giveItemFromMe(ore.give.name, ore.give.damage, givePreIteration)
- totalGive = totalGive + gived
- if gived == 0 then
- gpu.fill(1, h - 15, w, 2, " ")
- center(h - 15, "Oсвободите место в инвентаре", 0xff0000)
- center(h - 14, "Ожидаю выдать " .. tostring(toGive - totalGive) .. " " .. ore[2], 0xFFFFFF)
- os.sleep(1)
- end
- gpu.fill(1, h - 15, 2, h, " ")
- end
- end
- local function exchangeOre(slot, ore, player)
- local curSlot = pim.getStackInSlot(slot)
- if curSlot == nil then
- gpu.fill(1, h - 14, w, 1, " ")
- center(h - 14, "Вы сошли с PIM, обмен прерван. (Не удалось прочесть слот)", 0xff0000)
- log("Вы сошли с PIM, обмен прерван. (Не удалось прочесть слот)", "error", player)
- os.sleep(0.5)
- return
- end
- local userOreQty = curSlot.qty
- local takeQty = userOreQty - (userOreQty % ore.rate.take)
- local giveQty = userOreQty * ore.rate.give
- if ore.qty < giveQty then
- gpu.fill(1, h - 14, w, 1, " ")
- center(h - 14, "Недостаточно слитков для обмена <" .. ore[1] .. ">", 0xff0000)
- log("Недостаточно слитков для обмена <" .. ore[1] .. ">", "warning", player)
- os.sleep(0.5)
- return
- end
- -- Количество могло измениться..
- local takedOre = pim.pushItem("DOWN", slot, takeQty)
- if takedOre == nil then
- gpu.fill(1, h - 14, w, 1, " ")
- center(h - 14, "Вы сошли с PIM, обмен прерван. (Не удалось извлечь руду)", 0xff0000)
- log("Ошибка извлечения руды из PIM", "error", player)
- os.sleep(0.5)
- elseif takedOre == 0 then
- gpu.fill(1, h - 14, w, 1, " ")
- center(h - 14, "В выбраном слоте руды нет.. А была.. Хмм...", 0x505050)
- log("В выбраном слоте руды нет", "warning", player)
- else
- local giveQty = (takedOre // ore.rate.take) * ore.rate.give
- gpu.fill(1, h - 15, w, 2, " ")
- -- Анимация движения стрелки
- local baseText = "Меняю " .. takedOre .. " " .. ore[1] .. " на " .. giveQty .. " " .. ore[2] .. " "
- local arrowFrames = {"→ ", " → ", " →"}
- for frame = 1, 6 do
- local idx = (frame - 1) % #arrowFrames + 1
- gpu.setForeground(frame % 2 == 1 and colors.warning or colors.info)
- center(h - 14, baseText .. arrowFrames[idx], colors.subtitle)
- os.sleep(0.12)
- end
- -- Добавляем статистику
- stats.exchanges = stats.exchanges + 1
- stats.totalOre = stats.totalOre + takedOre
- stats.totalIngots = stats.totalIngots + giveQty
- log("Обмен: " .. takedOre .. " " .. ore[1] .. " на " .. giveQty .. " " .. ore[2], "info", player)
- giveIngot(giveQty, ore)
- gpu.fill(1, h - 3, w, 1, " ")
- center(h - 3, string.format("Всего обменов: %d | Руды: %d | Слитков: %d", stats.exchanges, stats.totalOre, stats.totalIngots), colors.info)
- end
- end
- local function checkInventory(player)
- local size = pim.getInventorySize()
- local ok, data = pcall(pim.getAllStacks, 0)
- if not ok or not data then
- gpu.fill(1, h - 14, w, 1, " ")
- center(h - 14, "Ошибка получения инвентаря PIM", 0xff0000)
- log("Ошибка получения инвентаря PIM", "error", player)
- os.sleep(1)
- return
- end
- for slot = 1, size do
- if data[slot] then
- for i, ore in pairs(ore_dict) do
- if data[slot].id == ore.take.name and data[slot].dmg == ore.take.damage then
- exchangeOre(slot, ore, player)
- end
- end
- end
- end
- updateOres()
- if pim.getInventoryName() ~= "pim" then
- gpu.fill(1, h - 15, w, 2, " ")
- center(h - 15, "Обмен окончен! Приходите ещё!", colors.subtitle)
- log("Обмен окончен!", "info", player)
- -- checkInventory() -- убираем рекурсию!
- else
- event.push("player_off", player)
- end
- end
- local eventHandlers = {
- interrupted = function()
- gpu.setBackground(defBG)
- gpu.setForeground(defFG)
- gpu.fill(1, 1, w, h, " ")
- os.exit()
- return true
- end,
- player_on = function(...)
- if not canProcess() then return end
- local args = {...}
- local player = args[1] or "Игрок"
- gpu.fill(1, h - 15, w, 1, " ")
- center(h - 15, "Приветствую, " .. player .. "! Начинаю обмен", colors.subtitle)
- log("Игрок " .. player .. " начал обмен", "info", player)
- updateOres()
- checkInventory(player)
- end,
- player_off = function(...)
- if not canProcess() then return end
- local args = {...}
- local player = args[1] or "Игрок"
- -- Очищаем экран и показываем только логотип
- gpu.fill(1, 1, w, h, " ")
- animateLogo(img, 1, h - 13, colors.title, 0.03)
- -- Выводим статистику обменов
- center(h - 3, string.format("Всего обменов: %d | Руды: %d | Слитков: %d", stats.exchanges, stats.totalOre, stats.totalIngots), colors.info)
- center(h, "Powered by DemonAve", colors.powered)
- log("Игрок " .. player .. " завершил обмен", "info", player)
- -- Не вызываем updateOres, чтобы не перерисовывать таблицу на экране выхода
- end
- }
- function handleEvent(eventID, ...)
- local handler = eventHandlers[eventID]
- if handler then
- return handler(...)
- end
- end
- function drawStat()
- gpu.setForeground(0x444444)
- gpu.set(
- 2,
- h - 1,
- string.format(
- "RAM: %.1fkB / %.1fkB",
- (computer.totalMemory() - computer.freeMemory()) / 1024,
- computer.totalMemory() / 1024
- )
- )
- end
- local oreTimeFn = function()
- updateOres()
- -- Каджый 10 такт обновляем экран
- for i = 1, 10 do
- coroutine.yield()
- end
- end
- local oreTimer = coroutine.create(oreTimeFn)
- function draw_img(img, x, y, fore, back)
- fore = fore or 0xffffff
- back = back or 0x0
- oldFG = gpu.getForeground()
- gpu.setForeground(fore)
- local i = 0
- for line in img:gmatch("([^\n]*)\n?") do
- gpu.set(x, y + i, line)
- i = i + 1
- end
- gpu.setForeground(oldFG)
- end
- -- ...existing code...
- -- Проверяем наличие необходимых компонентов
- if not me then
- center(h - 15, "Ошибка: ME интерфейс не найден!", 0xff0000)
- os.exit()
- end
- if not pim then
- center(h - 15, "Ошибка: PIM (Player Interface) не найден!", 0xff0000)
- os.exit()
- end
- -- Стартовый экран с анимацией
- gpu.setBackground(colors.bg)
- gpu.fill(1, 1, w, h, " ")
- animateLogo(img, 1, h - 13, colors.title, 0.01, true)
- center(h - 15, "Для обмена встаньте на PIM и не сходите до окончания обмена", colors.subtitle)
- showGreeting()
- -- Выводим статистику обменов
- center(h - 3, string.format("Всего обменов: %d | Руды: %d | Слитков: %d", stats.exchanges, stats.totalOre, stats.totalIngots), colors.info)
- -- Powered by DemonAve (по центру)
- center(h, "Powered by DemonAve", colors.powered)
- while true do
- drawStat()
- -- Очистка памяти при необходимости
- if computer.freeMemory() < 1024 then
- collectGarbage()
- end
- -- Обновление данных по таймеру
- if shouldUpdate() then
- updateOres()
- end
- local ev = {event.pull(1)}
- handleEvent(ev[1], table.unpack(ev, 2))
- if coroutine.status(oreTimer) == "dead" then
- oreTimer = coroutine.create(oreTimeFn)
- else
- coroutine.resume(oreTimer)
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement