Цифровой "Банк опыта" в Майнкрафт.
Некоторое время назад обнаружил мод Exp Chest.
Для версии 1.7.10, как и в частности для режима мультиплеера, судя по всему, этого мода нет в принципе. Вот и появилась "хотелка" реализовать данный мод на сервере в виде Админ-хранилища.
Игроки смогут весь опыт быстренько сгрузить на хранение или взять (весь или его часть, как угодно) Значение банковских ячеек привязано к базе SQL.
На проекте также ведется разработка данной программы игроком Asummonster и, возможно, др. игроками. Вариант реализации можно посмотреть здесь.
Эту программку я сделал так, как ее представил с самого начала и просил игроков, максимально повторить мод.
Видео: ВИДЕО
Версия 0.1.1: http://pastebin.com/ASu4szwH
Код: (реальные пароли и имя скрипта спрятаны в целях безопасности):
------------------------------------------------------ Программа -- -- для хранения опыта в Майнкрафт ---- с привязкой к базе SQL -- -- проект http://computercraft.ru -- -- 2015, © AlexCC -- ----------------------------------------------------local event=require("event")local term=require("term")local unicode=require("unicode")local computer=require("computer")local component=require("component")local radar=component.openperipheral_sensorlocal cb=component.command_blocklocal gpu=component.gpulocal inet = component.internetgpu.setDepth(4)-- константыlocal VERSION = "0.1.1"local KEY = '1111111qwerty55555'-- Varlocal expPers = 0local expBank = 0local CLIENT = nillocal TRANSFERCOUNT = 50-- ========= Кнопки ============ --Button = {}Button.__index = Buttonfunction Button.new(func, x, y, text, fore, back, width, nu) self = setmetatable({}, Button) self.form = '[ ' if width == nil then width = 0 else width = (width - unicode.len(text))-4 end for i=1, math.floor(width/2) do self.form = self.form.. ' ' end self.form = self.form..text for i=1, math.ceil(width/2) do self.form = self.form.. ' ' end self.form = self.form..' ]' self.func = func self.x = math.floor(x); self.y = math.floor(y) self.fore = fore self.back = back self.visible = true self.notupdate = nu or false return selfendfunction Button:draw(fore, back) if self.visible then local fore = fore or self.fore local back = back or self.back gpu.setForeground(fore) gpu.setBackground(back) gpu.set(self.x, self.y, self.form) endendfunction Button:click(x, y) if self.visible then if y == self.y then if x >= self.x and x < self.x + unicode.len(self.form) then self:draw(self.back, self.fore) local data = self.func() if not self.notupdate then self:draw() end return true, data end end end return falseendfunction buttonNew(buttons, func, x, y, text, fore, back, width, notupdate) button = Button.new(func, x, y, text, fore, back, width, notupdate) table.insert(buttons, button) return buttonendfunction buttonsDraw(buttons) for i=1, #buttons do buttons[i]:draw() endendfunction buttonsClick(buttons, x, y) for i=1, #buttons do ok, data = buttons[i]:click(x, y) if ok then return data end end return nilend--===================================--function setCenterText(y, w, text) len=unicode.len(text) local x=(w/2)-(len/2) gpu.set(x, y, text)endfunction runCommand(str) -- наша КБ-шка, куда же без нее cb.setCommand(str) cb.executeCommand()endfunction get(url) -- получить ответ от сервера (опыт из базы SQL) local request, reason = inet.request(url) if not request then return false end local text = '' while true do local data, reason = request.read() if not data then request.close() break elseif #data > 0 then text = text..data end end return textendfunction getBankExp(nick) -- получение значения опыта в банке (SQL) return get('http://computercraft.ru/.../*************.php?type=exp&auth='..KEY..'&nick='..nick..'&action=get')endfunction addBankExp(nick, amount) -- прибавить опыт на счет (SQL) return get('http://computercraft.ru/.../*************.php?type=exp&auth='..KEY..'&nick='..nick..'&action=add&value='..amount)endfunction giveUserExp(nick, exp) -- выдать опыт клиенту через КБ runCommand("xp "..exp.." "..nick)endfunction setNullUserExp(nick, lvl) -- обнулить опыт клиенту runCommand("xp -"..lvl.."L "..nick)endfunction getUserExp(nick) -- получить текущий опыт клиента (радар OpenPeripheral) local currentExp local exp = radar.getPlayerByName(nick).all().player.experience if exp.level >= 31 then currentExp = 3.5*exp.level^2-151.5*exp.level+2220 elseif exp.level >= 16 and exp.level <= 30 then currentExp = 1.5*exp.level^2 - 29.5*exp.level + 360 elseif exp.level<=15 then currentExp = 17*exp.level end -- вернем полный опыт в абсолютных единицах, а также текущий уровень return math.floor(exp.levelProgress*exp.nextLevelXp + currentExp) , exp.levelendfunction clearSetScr(x,y) -- чистим экранчик gpu.setForeground(0xffffff) gpu.setBackground(0x000000) gpu.setResolution(x,y) term.clear()end function drawGuestWindow() -- рисуем гостевое окошко, чистим пользователей, трансфер в "серединку" users={computer.users()} for i=1, #users do computer.removeUser(users[i]) end clearSetScr(44,20) gpu.setForeground(0x0000ff) print([[ ______ _ | ___ \ | | | |_/ / __ _ _ __ | | __ | ___ \/ _` | '_ \| |/ / | |_/ / (_| | | | | < \____/ \__,_|_| |_|_|\_\ _____ ______ | ___| | ___ \ | |____ _| |_/ / | __\ \/ / __/ | |___> <| | \____/_/\_\_| ]]) gpu.setForeground(0x0000ff) setCenterText(18, 44,' Банк опыта ☭, ©AlexCC') setCenterText(19,44,' Проект http://computercraft.ru, 2015') buttonsDraw(guestButtons) TRANSFERCOUNT = 50endfunction drawMineWindow() -- рисуем основное окошко для трансфера, лочим ПК на клиента computer.addUser(CLIENT) expPers, current_lvl = getUserExp(CLIENT) expBank = getBankExp(CLIENT) clearSetScr(40,14) gpu.setBackground(0x1e1e1e) gpu.fill(1,1,40,6,' ') gpu.setForeground(0xffffff) setCenterText(2,40,' Привет, '..CLIENT..'!') gpu.setForeground(0xffdb00) gpu.set(6,3,'Ваш опыт в Банке: '..expBank..' ед.') gpu.set(6,4,'Ваш текущий опыт: '..expPers..' ед.') gpu.set(6,5,'Ваш текущий уровень: '..current_lvl) gpu.set(1,1,"╔") gpu.set(40,1,"╗") gpu.set(1,6,"╚") gpu.set(40,6,"╝") for i = 2, 5 do gpu.set(1, i,"║") gpu.set(40, i,"║") end gpu.set(2,1, string.rep("═",38)) gpu.set(2,6, string.rep("═",38)) gpu.setBackground(0x000000) gpu.setForeground(0xffffff) gpu.set(19, 8, TRANSFERCOUNT..' %') buttonsDraw(menuButtons)endfunction transferExpToUser() -- клиент снимает с банка опыт expPers, current_lvl = getUserExp(CLIENT) -- уточним еще раз опыт клиента, он мог измениться при открытой сессии(клиент выпил бутылочку опыта или убил паука рядом) local trans_exp = math.floor(TRANSFERCOUNT * expBank/100) giveUserExp(CLIENT, trans_exp) addBankExp(CLIENT, -trans_exp) drawMineWindow()endfunction transferExpToBank() -- клиент отправляет опыт в банк на хранение expPers, current_lvl = getUserExp(CLIENT) local trans_exp = math.floor(TRANSFERCOUNT * expPers/100) setNullUserExp(CLIENT, current_lvl + 1) -- обнулим весь опыт giveUserExp(CLIENT, expPers - trans_exp) -- и выдадим разницу, что было и что отправлено addBankExp(CLIENT, trans_exp) -- отправим в банк опыт игрока, который он выбрал в процентном соотношении drawMineWindow()endfunction min1() -- уменьшить значение трансфера TRANSFERCOUNT = TRANSFERCOUNT - 1 if TRANSFERCOUNT < 0 then TRANSFERCOUNT = 0 end drawTransfer()endfunction min10() -- уменьшить значение трансфера TRANSFERCOUNT = TRANSFERCOUNT - 10 if TRANSFERCOUNT < 0 then TRANSFERCOUNT = 0 end drawTransfer()endfunction plus1() -- увеличить значение трансфера TRANSFERCOUNT = TRANSFERCOUNT + 1 if TRANSFERCOUNT > 100 then TRANSFERCOUNT = 100 end drawTransfer()endfunction plus10() -- увеличить значение трансфера TRANSFERCOUNT = TRANSFERCOUNT + 10 if TRANSFERCOUNT > 100 then TRANSFERCOUNT = 100 end drawTransfer()endfunction drawTransfer() -- нарисовать текущее значение процентика перевода опыта gpu.setForeground(0xffffff) gpu.setBackground(0x000000) gpu.fill(19,8, 5, 1,' ') gpu.set(19, 8, TRANSFERCOUNT..' %')endfunction operatiOnOnBank() -- цикл операций с опытом, пока не сдохнет ивентпулл или клиент не выйдет в гостевое окно drawMineWindow() while true do local name, address, x, y = event.pull(60, 'touch') if name == 'touch' then local result = buttonsClick(menuButtons, x, y) if result == 'exit' then break end else break end endend-- тут будут храниться кнопки (группы кнопок)menuButtons = {}guestButtons = {}-- рисуем кнопкиbuttonNew(guestButtons, operatiOnOnBank, 13, 15, " НАЧАТЬ РАБОТУ ", 0xFFFFFF, 0x0000FF, 11)buttonNew(menuButtons, min10, 2, 8, "-10", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, min1, 10, 8, "-1", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, plus1, 26, 8, "+1", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, plus10, 33, 8, "+10", 0xFFFFFF, 0x0000FF, 4)buttonNew(menuButtons, transferExpToBank, 8, 10, " Положить опыт в Банк ", 0xFFFFFF, 0x0000FF, 20)buttonNew(menuButtons, transferExpToUser, 8, 12, " Забрать опыт из Банка ", 0xFFFFFF, 0x0000FF, 20)buttonNew(menuButtons, function() return 'exit' end, 16, 14, " Выход ", 0xFFFFFF, 0xFF0000, 10)-- главный цикл программы, висит гостевое окно, ПК ни на кого не залоченwhile true do drawGuestWindow() local e, _, x, y, _, nick = event.pull('touch') -- если был клик мышкой - проверяем кнопки if e == 'touch' then CLIENT = nick buttonsClick(guestButtons, x, y) endend
ВНИМАНИЕ! В данной реализации программы использовано подключение к SQL. Но можно организовать и локальное файловое хранилище клиентской базы в игре, не используя внешние структуры данных.
Код скрипта (пример):
<?php // Пример запроса на добавление экспы или получение ее текущего значения // http://localhost/expupd.php?&auth=f92b3037ee&nick=Alex&action=add&value=10 // http://localhost/expupd.php?&auth=f92b3037ee&nick=Bob&action=add&value=-570 // http://localhost/expupd.php?&auth=f92b3037ee&nick=Bob&action=get // Получаем переменные в GET запросе: $username = htmlspecialchars($_GET['nick']); $action = htmlspecialchars($_GET['action']); $value = htmlspecialchars($_GET['value']); $auth = htmlspecialchars($_GET['auth']); // Проверим пароль доступа к скрипту и и некоторые параметры запроса: $codeaccess = 'f92b3037ee'; if ($auth != $codeaccess) die ("Wrong auth"); // В имени пользователя могут быть только цифры, буквы и знак нижнего подчеркивания if (!preg_match("/^[a-zA-Z0-9_]+$/", $username)) die("Bad login"); if ($action != 'set' and $action != 'get' and $action != 'add') die("Wrong action"); // Параметры подключения к базе: $host = 'localhost'; $user = 'alexcc'; // имя пользователя базы $pass = 'SFJHwhP6RrSaz'; //пароль к базе $namebase = 'prog'; // имя базы $table = 'test'; // имя таблицы // Подключение к базе $connect = mysql_connect($host, $user, $pass) or die('error connect'); mysql_select_db($namebase, $connect); $sql = mysql_query("SELECT exp FROM $table WHERE nick = '$username'") or die (mysql_error()); $count = mysql_num_rows($sql); // Если такого пользователя нет еще в базе, создадим его, и присвоем значение опыта 0 if ($count == 0) { mysql_query("INSERT INTO $table (`nick`, `exp`, `lastaccess`) VALUES ('$username', '0', NOW())") or die (mysql_error()); } // Вернем значение опыта if($action == 'get') { $sql = mysql_query("SELECT exp FROM $table WHERE `nick`='$username'") or die (mysql_error()); $data = mysql_fetch_array($sql); echo $data['exp']; } // Добавим или отнимем (если значение отрицательное) опыт if($action == 'add') { mysql_query("UPDATE $table SET exp = exp + '$value' WHERE `nick`='$username'") or die (mysql_error()); echo 'OK'; } // Чит фича (установка конкретного значения опыта) if($action == 'set') { mysql_query("UPDATE $table SET exp ='$value' WHERE `nick`='$username'") or die (mysql_error()); echo 'OK'; } // Закроем соединение с базой mysql_close($connect);?>
Пример базы:
В будущем, когда на ИТ будет введено ограничение на использование сложных технологий (например ядерных) игрокам накопитель опыта очень пригодится. Только потратив огромное его количество, игрок сможет получить квалификацию физика-ядерщика и только тогда сможет работать с ядерными технологиями и прочее.
Замеченные багульки и неточности просьба оставлять в комментариях.
- 4
7 комментариев
Рекомендуемые комментарии