Перейти к содержимому

astral17

Пользователи
  • Публикации

    76
  • Зарегистрирован

  • Посещение

  • Победитель дней

    7

Сообщения, опубликованные пользователем astral17


  1. В 14.01.2022 в 16:49, ECS сказал:

    Оставлю свои пять копеек для тех, кому нужно генерировать рандомные числа фиксированной длины. Хотя к теме это относится опосредованно, но мало ли:

    
    -- Вариант 1
    local function fixedLengthRandom(digits)
      digits = 10 ^ (digits - 1)
      return math.random(digits, digits * 10)
    end
    
    -- Вариант 2
    local function fixedLengthRandom(digits)
      digits = 10 ^ digits
      return math.floor(digits + math.random() * (digits - 1))
    end

     

    Только они чутка бракованные. В первом варианте поскольку рандом с границами генерирует включительно, иногда генерирует на 1 цифру больше, т. е. [1; 10], [10; 100] и т. д. А во втором варианте оно вообще фигню делает, [10; 18], [100; 198] и т. д.

    Ну и чутка бессмысленный момент: 0 это число длины 1, а должна ли функция его генерировать?


  2. Tree() - собирает дерево, у нас цикл в цикле, получается соберёт 10 * 5 = 50 деревьев. Судя по условиям ты считаешь, что x это номер рассматриваемого дерева, тогда что такое "a"? (есть догадки, что это количество рядов, но учитывая, что нету кода перехода между ними, то это вряд ли правда), если убрать этот цикл, то получится код, который пробегается ровно 5 различных деревьев из изначального ряда, причём 6 раз обобрав последнее, не катит. Кстати, интересный факт, x не может быть одновременно и меньше и равным числу 5, а в коде ты это явно просишь

    if x < 5 then
      ToTree()
      if x == 5 then
        robot.turnAround()
        robot.forward()
      end
    end

    Вообще зачем проверять тебе, меньше ли x, чем 5 не понятно, поэтому эта строчка явно лишняя, т.к. она мешает передвигаться к следующему дереву, убрав её получим код, который полностью пробежится по целому ряду в одну сторону и обратно. Но нужно помнить, что робот будет развёрнут в обратную сторону относительно момента до запуска функции.

    Однако, судя по схеме между деревьями 1 блок, тогда зачем в развороте forward ?

    Вообще всякие магические числа в коде для читабельности желательно избегать или хотя бы описывать, что они означают (если не совсем очевидные конечно). Ну и код без отступов больно читать.


  3. Трудно что-то тут сказать, т. к. слишком мало информации. По возможности хотелось бы увидеть скрины как всё было поставлено, что внутри пк и скрин самой ошибки, список модов, которые были дополнительно установлены. Если при спавне компа командой он не был ни с чем соединён (т. е. полностью изолирован от других компонентов), и был произведён чисто запуск без смены комплектации, то возможно появился какой-то баг OpenComputers, хотя это маловероятно. Вообще единственное предположение пока возникает, что была произведена попытка запуститься с пустой дискеты (после крафта дискеты нужно потом объединить с книжкой OC, чтобы получить OpenOS).

    • Нравится 1

  4. @ArtHacker ну, там короче при загрузке защищается список таблиц, куда входит и os , однако либа filesystem не полностью загружается при загрузке из-за package.delay, например файлик boot/02_os.lua содержит в самом конце строчку

    require("package").delay(os, "/lib/core/full_filesystem.lua")

    а файл boot/90_filesystem.lua эту

    require("package").delay(fs, "/lib/core/full_filesystem.lua")

    ну, а теперь как именно работает эта функция, после её использования устанавливается временная метатаблица, которая после первого обращения к любому индексу этой таблицы самоудаляется и запускает файл, который указан вторым аргументом.

    Проблема возникает из-за того, что таблица os защищается (т.е. скрипт, который запустит full_filesystem стирается до своего запуска), а filesystem нет. Фиксить эту проблему можно перед защитой искусственно обратиться к какому-то рандомному индексу проблемных таблиц, хотя, очевидно, что такой метод это дикий костыль, хоть и простой в реализации.

    • Нравится 1

  5. ммм, у нас походу немного разное понятие boot было, я подумал, что кинуть файл в /boot/*.lua , но вижу был не прав. Однако согласен, что я не заметил, что package.loaded присваивается от локальной и от неё работает, в этом моя ошибка. Однако это остаётся актуальным.

    1 час назад, astral17 сказал:

    Предположим, что это сработало, никто до сих пор не мешает подменить функцию require и при вызове require("tprotect") заменить на своё. Или заменить _G.package на другую таблицу.

    Замена _G.package может сработать против тех, кто не доверяет require и идёт напрямик. При изменении /lib/core/boot.lua всё нормально запустилось.

    UPD:
    И если что, я не говорю, что именно ты должен сделать эту защиту, я говорю, что ты должен помочь тем, кто захочет это сделать, ведь использовать набор методов из библиотеки гораздо проще, чем написать её с нуля

    Цитата

    Однако основная мысль прошлого сообщения была в добавке возможности защиты частичной таблиц, т.е. чтобы только некоторые поля были readonly , что позволило бы юзеру с гораздо меньшими усилиями защититься от всего перечисленного выше. Однако хозяин - барин, автор библиотеки не я, поэтому и не я выбираю, что в ней будет, а только предлагаю.

     


  6. 51 минуту назад, Kimapr сказал:

    Я такое в Kion в init поставил и все работает нормально. У библы package есть свой оригинал package.loaded, и он хранится в локальной переменной. Посмотри на код из /lib/package.lua:

    
    local loaded = {
      ["_G"] = _G,
      ["bit32"] = bit32,
      ["coroutine"] = coroutine,
      ["math"] = math,
      ["os"] = os,
      ["package"] = package,
      ["string"] = string,
      ["table"] = table
    }
    package.loaded = loaded

    А защита _G сломает некоторые программы к чертям. В _G нельзя будет писать, но это ещё не всё! Просто переопределив _G

    
    _G=tprotect.protect(_G)

    Ничего не получится. Защищена будет только сама переменная, но не таблица глобального окружения. Её нужно будет менять для каждой прожки. В таком случае лучше каждой программе сделать свое глобальное окружение. Это будет легче. А там пусть какую-угодно фигню творят, лишь бы out of memory не было (при должной защите, это единственный краш, который программа сможет нанести системе).

    На счёт сломается система, запускал на OpenOS 1.7.2 в boot tprotect не становился глобальной переменной, поэтому RE был, ок, заменил первую строчку на tprotect = require ... , система зависла и отказалась загружаться. Ок попробуем не из boot запустить, а как обычный файл..., ммм эпик фэйл, команды консоли сломались, можно было идти глубже но зачем, ведь предложенные строчки для другой системы (а вообще, хоть у package есть оригинал на себя, у него не хранится отдельно оригинал на package.loaded , который становится readonly , но это опустим). Предположим, что это сработало, никто до сих пор не мешает подменить функцию require и при вызове require("tprotect") заменить на своё. Или заменить _G.package на другую таблицу. Именно из-за таких проблем я и написал

     

    6 часов назад, astral17 сказал:

    и это уже просто чисто для размышлений

    И это также отвечает на это:

    44 минуты назад, Kimapr сказал:

    И вообще, какого чёрта мы опустились до старта системы? Я вообще просто библиотечку для защиты таблиц сделал, а как её использовать - не моё дело (если я не являюсь пользователем, при разработке Kion - я являюсь им)

     

    Можно и дальше перечислять проблемы, но раз меня критикуют, я пожалуй откажусь.

    Однако основная мысль прошлого сообщения была в добавке возможности защиты частичной таблиц, т.е. чтобы только некоторые поля были readonly , что позволило бы юзеру с гораздо меньшими усилиями защититься от всего перечисленного выше. Однако хозяин - барин, автор библиотеки не я, поэтому и не я выбираю, что в ней будет, а только предлагаю.

     


  7. 6 минут назад, Kimapr сказал:

    Функция protect вместе с зеркалом таблицы возвращает метатаблицу зеркала (на самом деле нет, но она косвенно влияет на настоящую метатаблицу зеркала). Библиотеку нужно подгружать в начале работы системы! Можно вот такой код поместить в /boot/:

    
    require"tprotect"
    package.loaded.component = tprotect.protect(component)
    package.loaded.computer = tprotect.protect(computer)
    package.loaded.unicode = tprotect.protect(unicode)
    do
      local loaded=package.loaded
      local unloadable={component=true,computer=true,unicode=true,tprotect=true,filesystem=true}
      local raw_type=type
      function package.unload(name)
        assert(raw_type(name)=="string","bad argument #1 to package.unload (string expected, got "..raw_type(name)..")")
        if not unloadable[name] then
          package.loaded[name]=nil
        end
      end
    end
    package.loaded=tprotect.protect(package.loaded)
    _G.package=tprotect.protect(package)

    И постараться чтобы этот бутскрипт выполнился последним (предпологается, что другие бутскрипты хорошие и не вредные!). Еще можно реализовать права на файлы, как в *nix, но для этого я и пишу Kion (это ОСь такая). Чудо щас исправлю

    Если сделать package.loaded readonly то вся система сломается к чертям, т.к. не сможет загружать новые библиотеки и т.д. и т.п., ещё проблемка в том, что нужно в таком случае защищать и _G ведь кто мешает подменить package на другую таблицу?, затем кто мешает подменить функцию require ?, заменить require на костыль, который вместо tprotect вернёт заражённую копию?, так что тут как вариант добавить readonly поля по выбору, затем функция не возвращает метатаблицу зеркала, а возвращает метатаблицу оригинала. Когда говорил, что иногда хотелось бы видеть метатаблицы, я имел ввиду через getmetatable . Ну а вообще, для другой системы может и будет внутренняя защита от таких вещей, но это нужно смотреть на то, какая структура будет.


  8. Ну, из уязвимостей вроде бы и всё, конечно же проблема до сих пор возникает "как получить эту библиотеку, если зловред уже работает", т.е. он может спокойно подменить require , package и т.д. , т.е. даже если библиотека загружена, ты не можешь удостовериться в том, что это правда она, однако то, что сама таблица защищена уже гарантирует, что те, кто получил её не обнаружат сюрприз. Как фиксить такое фз, и это уже просто чисто для размышлений (но было бы неплохо, если можно было подтвердить).

    Было бы неплохо, если сам код был под спойлером в теге "код".

    Как знаешь, в таблицах, которые хочешь защитить могут находиться также и другие таблицы. Иногда хочется защитить и их (но не всегда), поэтому хотелось бы видеть функцию, которая будет рекурсивно защищать все таблицы от изменений, которые есть в защищаемой таблице. (не забудь про возможность зацикливания, например в защищаемой таблице может вдруг оказаться ссылка на её саму).

    Ну и на последок, то, что в getmetatable от зеркала возвращается строка защитная, не очень хорошо, иногда хотелось бы видеть метатаблицу, оригинальной (конечно же readonly), тут тогда возникает вопрос, до какой глубины идти?, ответ: до тех пор, пока есть метатаблица у метатаблицы и она ещё не защищена (в кратце расширение к рекурсивной защите). В принципе это будет создавать дополнительные нагрузки на память, поэтому можно поставить флажок, нужно ли так делать.

    Вроде бы большего ожидать от этой библиотеки смысла скорее всего нету (до тех пор, пока она касается только защиты таблиц). А за старания респект.

    UPD:
    короче, нужен багфикс сего чуда

    pLReZSn.png

    Если вкратце, то при обращении к метаметодам зеркала получается, что оно берёт сырые значения из метатаблицы (вот как раз таки причина, почему у меня не удалась та атака с __add , ну да ладно, она хотя бы показала, что в теории любая глобальная переменная может быть злом), а это может оказаться довольно довольно важной вещью таблицы (т.е. нужно сделать будет редирект всех метаметодов, либо изменить структуру работы).

    • Нравится 1

  9. Дубль 2, короче сдаюсь в этот раз получилось гораздо качественнее, уязвимости есть, но не очень критические и легко фиксятся.

     

    KbtxmIv.png

    Так сказать защита rawset не очень хороша), а если точнее, то error не обязательно выходит из функции, например если сделать так, как на скрине, то сразу понятно, что код продолжит работу. Т.е. нужно либо хранить персональный error , либо дописать везде return nil или что-то похожее), похожая проблема с getmetatable и setmetatable , т.е. если их переписать, то получится, что мы сможем выхукнуть таблицы в момент их защиты.

    Также это дело касается type , т.к. я могу обломать валидацию mto на таблицу и запихнуть через __metatable функцию, т.е. tcopy_mt = mto = myfunction , а если __index это функция, то при обращении к метатаблице я смогу получить и саму чистую метатаблицу, т.е. mt, а сама она никак не защищена, как сиё сделать, (цель вообще вытянуть protectid) , смотрим, нам нужно обратиться в mt к значению, которого нету например _add , а значит вызывается __index в который помещается mt, "__add" и тут мы и хукаем mt. (как вытянуть не проверялось, и писалось почти с закрытыми глазами, так что скорее всего сиё чудо только в теории, завтра чекну)

    • Нравится 2

  10. 24.01.2019 в 16:22, Kimapr сказал:

    if getmetatable(t).isOpened(protectid)

    Интересная защита), сломать функцию rawset , чтобы она не работала) т.е. она получает метатаблицу и запускает функцию в ней, во-первых если метатаблицы нету, краш), если метатаблица есть, то всё равно краш, т.к. в ней нету этой функции)

    Затем tprotect.open не работает, причина проста, mto может равняться nil , т.е. если создать чистую таблицу, и её защитить, получим epic fail...

    возвращаемая таблица через getmetatable(ptbl) , где было вызвано tprotect.protect(ptbl) является mt2 и её можно редактировать, такая же проблема вообще и на саму ptbl распространяется, т.к. __newindex работает только в случае, если такого ключа нету, если ключ есть, то нужно использовать __index , однако получив таблицу mt2 даже с доступом на чтение мы сможем спокойно выудить все значения, и protectid и списочек nonpi (я так и не понял, зачем он вообще нужен, как вариант посолить, чтобы сложнее было вытянуть protectid, но в таком случае слишком мало соли). Вообще protectid можно получить просто через tprotect.isProtected , т.к. там получается метатаблица у таблицы, которую мы передаём внутрь и обращается по индексу protectid , т.е. секретным назвать его трудно.

    Но вернёмся к нашим баранам, mt2 допустим у неё есть __index тоже, значит we need to go deeper , смотрим на метатаблицу mt2, она не защищена, т.е. её можно спокойно изменять и мы видим спокойно все её значения

    Скрытый текст

    RhMnCyn.png

    снимаем защиту на изменение mt2 -> profit 

    24.01.2019 в 16:22, Kimapr сказал:

    if getmetatable(t).isOpened(protectid) or ((not tprotect.isProtected(t)) and not cantrawset) then

    возвращаемся сюда, порядок в lua слева на право, т.е. в начале оно споткнётся об nil , а потом проверит, а защищалась ли таблица вообще?, т.е. нужно поменять местами для начала

    if ((not tprotect.isProtected(t)) and not cantrawset) or getmetatable(t).isOpened(protectid) then

    если не защищено, то оно не будет пытать метаметод isOpened , однако mt2 мы можем спокойно редактировать, т.е. isProtected и cantrawset мы можем управлять их значениями.

    Ещё можно атакуемую таблицу заменить на свою таблицу, дождаться пока её не попробуют открыть, и таким образом заполучить ключ (MitM attack)

    Либо пойти более общим путём, раз getmetatable не сохраняется, то просто подменить его и вытянуть интересующие таблички в момент защиты, открытия и т.д. и т.п., либо в setmetatable сделать так, чтобы устанавливались во время защиты свои, т.е. их тоже нужно копировать и защищать)

    Затем функция open немного бесполезна, т.к. получается, что таблица на момент выполнения кода не защищена, лучше сделать вариацию, где возвращается таблица, изменяя которую изменяется оригинальная, причём защищённая таблица остаётся защищённой.

    Также сам tprotect тоже нужно защищать, т.к. перезаписать функции библиотеки хватит, чтобы сломать её защиту (функции хранятся в открытом виде в package, где можно спокойно подменить, и require будет возвращать её) , также require тоже нужно защищать. Т.е. по факту защита работает успешно только для защищённых ранее и не открывая доступ во время выполнения чего-то, что может иметь плохие желания.

    Ладно, пока что на этом хватит, резюмируя всё выше сказанное, её ещё пилить и пилить. А вообще возникает чувство, что автор её даже не проверял, т.к. работают только 2 функции protect и unprotect , а функция rawset вообще под чистую сломана. Ну надеюсь в следующей версии автор учтёт хотя бы часть написанного тута, и следующая версия библиотеки будет лучше.

    • Нравится 3

  11. Вопрос такой, будет ли интересно, если сделать продолжение этого квеста?), прост я себе написал списочек из 10 различных идей взлома банка (+ ещё есть пару мыслей, что можно добавить) и можно тогда будет сделать часть 2, где нужно будет взламывать целый ряд банков, с различными уровнями сложности, от просто послушать трафик, до приличной серии махинаций. В принципе реализовать всё это можно за пару дней (при наличии желания), однако стоит ли?

    • Нравится 1

  12. То чувство, когда автор карты сделал 2 уязвимости, а хакнул через 3ю 🤣, потом после хака я уже понял идею, как можно было хакнуть ещё причём проще, а когда смотрел уже код, я понял, что автор имел ввиду немного не те дыры (интересно то, что все 3 дыры находятся в разных частях кода), скорее всего первую он имел ввиду ту, которую можно сразу сделать без танцев с бубном,  а вторую это уже чисто удача или читать исходники. В принципе со стороны кубика, предназначенного для того, чтобы его ломали и разбирали то довольно не плохо, однако выводить в релиз как работоспособую и безопасную систему явно нельзя 😅

    • Нравится 1
    • Ха-ха 1

  13. Скорее всего значит у тебя установлена OpenOS 1.6.1 , а значит просто тебе нужно будет подменять event.shouldInterrupt

    local event = require("event")
    function DisableInterrupt()
    	if _G.shouldInterruptBackup then
    		return false
    	end
    	_G.shouldInterruptBackup = event.shouldInterrupt
    	event.shouldInterrupt = function() return false; end
    	return true
    end
    
    function EnableInterrupt()
    	if type(_G.shouldInterruptBackup) ~= "function" then
    		return false
    	end
    	event.shouldInterrupt = _G.shouldInterruptBackup
    	return true
    end

    вставляешь это в начало кода, а потом, когда нужно вызываешь функцию, которая тебе нужна (думаю это и так понятно), если и это не сработает. то тогда скажи, чему равна переменная _G._OSVERSION

    • Нравится 3

  14. Ну, перед тем, как задавать вопрос желательно поискать, задавался ли он до этого и есть ли на него ответ.

     http://computercraft.ru/topic/2396-kak-otklyuchit-ctrlaltc/?do=findComment&amp;comment=35069

    Если это не сработает, то нужно будет сказать, какая версия мода и OpenOS, ведь там меняли эту вещь. В начале была функция shouldInterrupt , потом её убрали и пришлось костылить, а в самой новой версии вернули возможность через обработку process.info().data.signal

     

    хмм, прочитав код и видя строчки

    for i = 1, 255 do
        print()
    end

    становится больно, эмм, зачем?? и что они должны делать?, очищать экран?, temp.clear() на что?

    Затем ещё табуляция есть не везде, например после while true do оно так и остаётся монотонным текстом, ну ладно, это я уже отошёл от темы.

    • Нравится 1
    • Грусть 1

  15. Только что, eu_tomat сказал:

    Возможно, не понял вопроса. На диск OC, разумеется. Какие ещё есть варианты? На HTTP сервер? Но как защититься от недобросовестных установщиков игры?

    ну, логично что на диске, я спрашивал про путь нахождения файлов, есть 2 пока что мысли по этому поводу, либо в ту же папку, где и сама игра и таким же названием файла ток на конце .cfg (для этого нужно будет посмотреть как там определить где находится файл), либо в какой-то фиксированный глобальный путь


  16. 1 минуту назад, eu_tomat сказал:

    Ну, если тебя устраивает минимализм, можешь посмотреть, как это устроено во всё том же Far Mine, плагине для файлового менеджера. Мой скриншот как раз в нём получен. Там при входе выбор из трёх вариантов сложности, горячие клавиши кроме выше перечисленных:

    F2: Restart (смена уровня сложности не предполагается до выхода из игры)

    F3: Highscore

    По окончании игры, если установлен рекорд, предлагается ввести имя. А в OC игра и так знает имя игрока, одним экраном будет меньше.

    ну, для минимализма нужно, чтобы пользователь знал заранее на что нажимать, думаю я просто добавлю кнопки сверху(или снизу), для этого, нужно будет глянуть что из этого получится, кстати есть еще вопрос, куда лучше сохранять конфиги и рекорды?


  17. 6 минут назад, eu_tomat сказал:

    Ближайшая ко мне консольная вариация сапёра.

    Красным фоном помечена текущая позиция. Управление стрелками на клавиатуре, можно и мышью тоже. Также:

    • Space/LBM: открыть клетку.
    • Del/RBM: пометить мину.
      Скрыть содержимое

     

    FDKvNKm.png

     

     

    Ну, у меня проблема в том, как размещать кнопки для менюшки выбора сложности, кнопку ввхода и т.п., в принципе если нужно, то могу модифицировать с монотонных клеток на чередующуюся сетку, что скорее всего будет лучше, есть еще вещь печальная, раньше знак мины у меня был знак радиации, однако после великой обновы шрифта его больше нету, сейчас я локально заменил на два полукруга (круг в ячейке 2х1)


  18. Update7(11.11.2018)

    Хотелось сделать больше, а получилось как всегда, но не суть

    1) Игра тетрис переписана под гуи и вроде выглядит даже нормально

    2) Аналогично и с крестиками-ноликами

    3) Теперь в тетрисе есть тень (которую можно включить и выключить в настройках), а также предсказание следующего блока

    4) В крестиках-ноликах теперь можно выбирать требовать ли авторизацию (т.е. если идёт чужой ход, то только игрок, зарегестрированный под него может ходить)

     

    Вообще я еще переписывал сапёр, но столкнулся об стенку, "как он должен выглядеть", и пока нету ни единой мысли об этом. Такая же (но меньше) проблема касается и Камень-Ножницы-Бумага. Наконец-то я заставил себя чуточку подредактировать главный пост и добавил план, по выполнению которого я скорее всего закончу с этой темой и уже буду заниматься другими вещами. Либа потиху растёт помолимся за обратную совместимость после апдейта, ведь я её не чекал.

    Скрытый текст

    dyXArwC.pngT4J8bVm.png4zkuxJ7.png

     

    • Нравится 1

  19. Update6(27.10.2018)

    Это изменение касается только игры MazeMaster

    1) Добавлено меню, а также куча настроек

    2) Добавлена функция "поиск пути", рабочая, однако отрисовка не доделана, если в настройках включена она, то срабатывает при нажатии "P"

    3) Добавлены маркеры, установить на пробел

    4) Пофикшены пара багов в генераторах, в рекурсивном теперь начинает из случайной точки, а в hunt&kill больше не может быть циклов

    5) Добавлена возможность изменения точки начала и конца

    6) На случай если либа, нужная не скачана, то предложит пользователю скачать её при наличии инет карты

    Скрытый текст

    9VE4bdr.pngRYwYtZZ.pngkMBc5P2.png

     

    • Нравится 4

  20. Короче, если вопрос еще актуален, код чуть ниже предоставляет 2 функции включить и выключить, никаких модификаций в библиотеках он не требует, т.е. достаточно вставить его куда-нибудь поближе к началу. Работает за счёт переопределения computer.pullSignal блокируя все ошибки изнутри.

    local computer = require("computer")
    local pullSignalBackup = nil
    
    local function DisableInterrupt()
      if pullSignalBackup ~= nil then
        return false
      end
      pullSignalBackup = computer.pullSignal
      computer.pullSignal = function(...)
        local tbl = {pcall(pullSignalBackup, ...)}
        return table.unpack(tbl, 2)
      end
      return true
    end
    
    local function EnableInterrupt()
      if pullSignalBackup == nil then
        return false
      end
      computer.pullSignal = pullSignalBackup
      pullSignalBackup = nil
      return true
    end
    
    • Нравится 2

  21. Оффтоп:

    Почему играм от программистов никогда не хватает графона?

    Ну, если ты сможешь предложить, как оно должно выглядеть лучше, я буду только за, сегодня этим как раз планирую заняться.


  22. Update5(17.07.2018)

    Итак, я вернулся спустя приличное время, если pastebin не врёт, то я написал SameGame аж еще 25.03.2018, однако на мой взгляд он был очень не завершён или еще что-то и я решил сюда не добавлять.

    1)Я и гуи злостные враги, однако чужое брать я очень не люблю, поэтому только что я завершил написание прототипа своего велосипеда лично для себя.

    2)Добавлена игра SameGame и она имеет (неожиданно) меню, настройки и нормальную кнопку выхода.

    К следующему разу (надеюсь завтра), я планирую запихнуть условие конца игры туда и таблицу рекордов, а также запихнуть менюшку ко всем играм (хотя код некоторых прям кричит ПЕРЕПИШИТЕ МЕНЯ)

    3)Перенёс все скрины на imgur

    Рандом пасты меня пугает..., что он курил, когда придумывал к SameGame строку.

    А еще меня интересует, как открепить старые прикреплённые файлы от сообщения?

    • Нравится 1

  23. Я хотел предложить 1D арену, намного меньше возни, а возможности те же, что и на текущей.

    а какой в этом смысл?) типа как дуэльки кто быстрее пульнёт тот и победил?) хотя впринципе можно что-нибудь такое умное реализовать типа есть несколько слоёв (допустим 5) нужно придумать такту в которой ты сможешь выстрелить и увернуться от пули врага потом как-нибудь просканировать жив ли враг, такая перестрелка получится. Как идея для UT#3 годится) правда в толщиной в 1 блок всё-таки не совсем будет место для манёвра толщины 3-5 должно хватить, также изначально роботы должны находиться спиной друг к другу, это нужно например для того чтобы если робот захотел отойти вбок,а другой решил сразу стрелять и было чтобы время отойти

×
×
  • Создать...