Алхимический натюрморт по мотивам The Elder Scrolls V: Skyrim. Алхимические ингредиенты, сумка, книжка алхимика и рисунки ингредиентов.
Автор: Deloto.






Сохраняй посты, комментируй и ставь оценки
Алхимический натюрморт по мотивам The Elder Scrolls V: Skyrim. Алхимические ингредиенты, сумка, книжка алхимика и рисунки ингредиентов.
Автор: Deloto.






Несколько предметов, которые могут понадобиться настоящему Monster Hunter`у.

"Вы стоите перед Утопией Драконов, местом, запретным для простых смертных. Хотите ли вы нарушить это правило и вызвать драконов на бой?"
Диорама по мотивам Heroes Of Might And Magic 3. Утопия Драконов. Места, где сокровища и артефакты охраняются несколькими драконами.
Автор: Deloto





Короткий познавательный пост, основанный на моей больной фантазии. Все совпадения случайны.
Обратился как-то один человек на профильном форуме с вопросом, как запустить (не сказать чтобы старую) игру на Windows 10. Игра (хотя я бы назвал это технодемо) была разработана на легендарном XNA 4.0 (земля пухом) и планировалась к выпуску через Steam Greenlight (и ему земля пухом) еще в далеком 2012, после чего заброшена и убрана со всех магазинов.
Игра была куплена тем человеком еще в тот момент, когда она легально продавалась. А спустя годы она просто перестала подавать признаки жизни. $5 за полную версию уплочены, а поиграть нельзя. Обидно.

Так как типовые решения по типу установки XNA Redistributable не помогли, то был предложен единственно возможный выход из ситуации - отладка через dnSpy.
Внимание: обратная разработка хоть прямо и не запрещена законодательно, но разрешенные случаи весьма ограниченны. В других странах разрешен явный запрет любых манипуляций через лицензию, превращающий это занятие во вполне наказуемое. Не повторяйте дома.
Так как ПО было приобретено легально и оно не работает, то этот теоретический случай допустим в соответствии со статьей 1280 гражданского кодекса.
Демонстрировать буду на бесплатной демоверсии, скачать можно здесь.

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

Ошибка. Открываем стек вызовов и ищем место, где произошел провальный запрос в сеть.

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

Если почитать документацию на XNA, то этот метод предназначен для загрузки контента и вызывается автоматически при запуске игры. Первым делом выполняется инициализация некоторых вещей, после чего открывается файл настроек (options.xml) и начинает последовательно считываться. Как только считываются параметры аккаунта для таблицы рекордов, то происходит отправка логина+пароля на официальный сайт и попытка получить ID. Если сервер возвращает Failure, то открывается диалог входа, который можно пропустить. Если сервер возвращает число, то игра запускается. А вот если сервер недоступен, то вылетает исключение, которое никак не обрабатывается и приводит к молчаливому вылету.

На этом этапе есть 2 варианта действий:
Нормальные герои всегда идут в обход, так что переходим к написанию небольшого патча. (На самом деле, о первом варианте я додумался не сразу. Более того, полная версия зависает при убирании этого пункта из настроек).
Выделяем строчку с запросом и нажимает "Изменить инструкции IL". Открывается окно с заголовком "Изменение тела метода".

Это - язык MSIL. Он очень прост и сильно напоминает Forth, на самом деле, но новичка может отпугнуть.
Ключевым элементом является стек. Что такое стек я уже когда-то рассказывал. Это некоторое место, на вершину которого можно последовательно добавлять значения (числа, строки и прочие объекты), а так же снимать их в обратном порядке.

Тут мы добавляем на стек:
Потом мы вызываем String::Concat(), принимающий в себя 4 строки и соединяющий их вместе. При вызове метода будут сняты 4 верхние строки со стека и добавлена новая строка.
Вызов следующего метода (WebClient::DownloadString()) снимает строку, полученную от String::Concat(), и веб-клиент. В результате должна остаться только 1 строка, возвращенная WebClient::DownloadString().
Следующим этапом мы должны снять эту строку со стека и сохранить её в локальную переменную 1, но этого не произойдет, так как WebClient::DownloadString() всегда будет проваливаться и выбрасывать исключение. Исключение, если его не обработать сразу, будет раз за разом проваливаться глубже по стеку вызовов, пока не достигнет обработчика или дна. Так как никаких обработчиков по пути нет, то исключение достигает дна и приводит к вылету.
Чтобы избежать получения исключения, мы можем убрать всё, что предназначено для запроса в сеть. Примерно вот так:

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


Из декомпилированного кода полностью исчез кусок с запросом. Осталась лишь загрузка константной строки и сравнение с "Failure", которое всегда будет успешным.
Сохраняем модуль и пытаемся запускать опять.



С этой задачей успешно справился человек, который не смыслит в программировании вообще ничего. По его словам, он джва года ждал эту игру!

Но не всё так просто. Если попытаться пройти любой уровень, то вылетит то же самое исключение.
Для исправления точно так же выделяем строку и опять редактируем инструкции в теле метода. Но так как отправка статистики нонче ни на что не влияет, то просто удаляем выделенные инструкции без остатка.
А для надежности выделяем WebClient, нажимаем "Анализировать" и смотрим, где еще может ждать нас подлянка.

В Finish.Update() мы ошибку только что исправили, в Game1.LoadContent() исправили в самом начале, а Login.button1_Click(), Program.Main() и Title.Update() нас не интересуют, так как достаточно просто не делать того, что приведет к обращению в сеть (а конкретно: не открывать диалог входа, не указывать никакие аргументы при запуске и не пытаться авторизоваться через главное меню (вроде бы не реализовано)).
Вуаля. Игра работает как прежде.
Я уже говорил тебе, что такое безумие? Безумие — это точное повторение одного и того же действия, раз за разом, в надежде на изменение. Это и есть безумие.
(с) Ваас Монтенегро
По просьбам в комментариях под прошлым постом продолжаем тему баланса игровых костей.
Для ЛЛ: 10 000 бросков кубиков с Ozon. Потом ещё столько же бросков кубиков из магазина настолок. Потом четыре онлайн-генераторов кубов, тоже по 10 к роллов для каждого. Подведение итогов.
Объект исследования:
1) кубики из магазина настольных игр, набор 10 штук (250 р набор, по 25 р каждый);
2) самые дешёвые кубики от Ozon, набор 8 шт (на момент заказа 104 р, т.е. по 13 р каждый);
Как бросал: чтобы исключить влияние оператора, из говна и палок плотного картона сделал dice tower (благо, схему в интернете найти легко). Фотографировать этот шедевр орочьей инженерии, с вашего позволения, не буду: свою функцию выполняет, при бросках не деформируется, но выглядит неказисто.
Кубики из магазина настолок: розового цвета, "для няшных варгеймов", как сказано на сайте. Не думаю, что со своими патлами и бородой я соответствую критериям няшности, но уж какие были в наличии. Размер: стандартные 16 мм. Материал: написано, что нефрит. Грани и углы хорошо сглажены: кубик катится долго, делая на столе не менее 5-6 оборотов. Матрица - правосторонняя. Материал не выглядит совершенно однородным, на гранях присутствует градиент цвета. Размер точек не отличается, сами точки залиты белой краской ниже уровня грани. Внешний вид:

Сравнение массы кубиков в наборе:

Кубики с Озона: меньше стандартных, всего 12 мм. 8 штук в наборе. Материал - АБС-пластик. Прозрачные, точки заглублены и маркированы красной, жёлтой и синей краской. Кубики, кажется, пытались сбалансировать: точка на грани 1 крупнее и глубже остальных. В толще материала 3 из 8 кубов имеют маленькие (менее 1 мм) пузырьки воздуха. Кубики с этим дефектом не исключал из выборки: проверим то, что пришло, "as is", никто ведь не будет рассматривать их так пристально во время игры. Грани и углы сглажены, куб катится хорошо. Матрица тоже правосторонняя. Внешний вид:

Сравнение массы:

Т.к. в обоих случаях масса кубиков в наборе очень близка, принял решение кидать кубики каждого типа вместе, по 10 и 8 штук, для ускорения набора статистики. Иначе, думаю, к концу эксперимента кукушечка у меня отлетела бы окончательно.
Выгоняем котов (очень уж им хотелось присоединиться к новой весёлой игре) и начинаем. Результаты - в этом файле Excel (Яндекс.Диск). Далее для наглядности полученные результаты отнесены к "идеальным" 16,67% (1/6, столбец "Δ от нормы"). Для оценки полученных результатов использовал, как предложил уважаемый @fakir22, критерий хи-квадрат, только расчёт выполнил через функцию ХИ2ТЕСТ.
Результаты бросков для кубиков из магазина настолок:

Максимальное отклонение от оптимального значения составило 3,40% (напомню, для кастомного кубика из предыдущего поста грань 6 выпадала на 9,74% чаще, а 1 - на 5,80% реже "положенного"). Для числа выпадений каждой грани RSD (n=6) 2,39%, χ^2 = 0,4451: опровергнуть гипотезу равной вероятности граней 1-6 не удалось.
Вытираем скупую мужскую слезу пот со лба, берём в руки кубики с Озона и бросаем их... правильно, ещё 10 000 раз. За окном уже брезжит рассвет и матерятся дворники. Результаты:

Признаться, я был удивлён. Самые дешёвые кубики, от которых не ждёшь никаких сюрпризов, показали весьма достойные результаты: RSD (n=6) 1,43%, χ^2 = 0,8891: очень... нет, ОЧЕНЬ хорошо. Очевидно, доказать неравновесность кубиков тоже не удалось. Кубики, по итогу, унёс на работу и раздарил коллегам (- Мужик, у тебя кубик есть? На, мужик, кубик).
В прошлый раз я сказал, что для нивелирования неравновесности физических дайсов стоит использовать онлайн-генераторы кубов. Чтобы не быть голословным, проверил четыре таких сайта из топа поисковика (те, что показывали полную выдачу по каждому "роллу": к этому моменту вносить результаты по одной цифре я был уже не в состоянии). Для каждого сайта делаем ещё по 10 000 "бросков" и переносим результаты в эксель.
Пикабу образовательный: теперь я знаю о возможности рассортировать данные из одной ячейки через опцию "Данные" - "Текст по столбцам" (может быть, кому-то пригодится). Полные результаты в расчётном файле по ссылке выше. Чтобы не растягивать, приведу только сводную таблицу (не реклама):

Т.о., все эти сайты дают правдоподобную картину случайного распределения результатов ролла.
Подведём итоги.
1) Если грани кубиков не имеют очевидных различий, скорее всего, распределение результатов ролла будет близко к нормальному (КАПИТАН ОЧЕВИДНОСТЬ, чёрт побери). Цена тут, вероятно, вторична.
2) При выборе кастомных костей надо быть очень осторожным. Некоторые мастера отдают предпочтение внешнему виду, по каким-то причинам (сложность ли производства, банальное попустительство или что-то ещё) забывая о балансе своих изделий.
3) Онлайн-генераторы (по крайней мере те, что я навскидку рассмотрел) дают вполне достоверную картину распределения вероятности выпадения костей. Но, разумеется, кому-то (мне, например) нравится момент бросания кубиков, в этом есть своя романтика.
Напоследок пара слов уважаемому (без сарказма) @cyberdicegames. Я ни в коем случае не ставлю под сомнение Ваше мастерство: безусловно, и кости и, особенно, коллекционные фигурки выглядят очень здорово, и я с интересом буду в дальнейшем следить за Вашими публикациями. Однако... Как там было сказано? Цитирую (орфография сохранена):
...когда мне пишут люди про баланс моих дайсов, обладая только теорией, (что у вас тут вырез на одной грани больше чем на другой и я УВЕРЕН ваши кубики НЕБАЛАНСНЫ), меня это всегда вызывает улыбку... все эти громкие заявления - пальца выделенного не стоят. ...все эти люди, кто так яро выражали своё мнение про баланс - имели в своих коллекциях огромное количество дайсов просто с ужасным балансом.
Пальца выделенного, мда... Ну что же, вот я из интереса потратил своё время и теперь обладаю не только теорией, но и кучей практики (даже больше, чем хотелось бы). Самые дешёвые кубики, купленные на Озоне и в первом попавшемся магазине настолок, оказались сбалансироваными. Случайные онлайн-генераторы кубов - тоже выдают адекватные результаты. Но баланс как минимум некоторых моделей Ваших кубов, которые стоят в 69 (!!!) раз дороже и которые Вы, по сути, рекламируете своими постами на Пикабу, объективно оставляет желать лучшего. Стильная, красивая, дорогая... игрушка.
Буду рад, если Вы аргументированно меня переубедите. Агрессивно отстаивая баланс своих дайсов, Вы раз за разом показываете кубик, насечки на гранях которого имеют равную длину (даже сделали, как я посмотрю, новую подпись к фото: "Perfect! Balanced Dice"). Вот только никто с этим и не спорил: например, ещё больше двух недель назад я говорил, что к этому кубику меньше всего вопросов. И даже Ваш эксперимент это подтверждает. Сомнения вызвали кубы с визуально различающейся длиной выточек, но все неудобные вопросы о них Вы игнорируете, приводите эмоциональные доводы без конкретных цифр или переходите на личности.
Вы заявляете: "самым важным элементом в моей работе является - качество", но отмахиваетесь от критики (я хотел, чтобы мои замечания были максимально обоснованными и конструктивными, сделав в общей сложности 30 000 физических роллов и 40 000 виртуальных): "мне не интересно доказывать элементарные вещи, которые каждый сам может осознать" и т.п. Это звучит инфантильно и непрофессионально.
Уважаемые @admoders, я надеюсь, размещение поста в сообществе не вызовет возражений. Спор начался здесь; к тому же, нельзя забывать: игрок, распределяя статы персонажа, предполагает, а судьба, которую олицетворяют игровые кубы, располагает. А судьба должна быть беспристрастной.
Приглашаются: @arrraarrra (вопрос о виртуальных дайсах), @Deha4444, @ghostabv, @Whateveryouwish, @KAKAOCMETAHA, @dildus, @arigatan и остальные, спрашивавшие про баланс магазинных кубов.
Бонус: "Хозяин, хватит кубиками стучать, и так жарко..."

UPD. Ветка с ответом мастера. Думаю, каждый сделает выводы сам.
Маленькая подборка зелий для ваших кампаний и модулей настольных игр.

1 - Холодная жидкость апельсинового цвета в флаконе из прозрачного кристалла-хрусталя. Она позволяет моментально прийти в себя, если персонаж пьян, и восстанавливает здоровье.
2 - Шипучая, серебристого цвета жидкость, находится в стеклянном браслете с пробкой, даёт иммунитет к страху и воодушевляет.
3 - Ярко-розовая, переливающаяся на свету жидкость в стеклянном шаре без отверстий - его нужно разбить, тогда жидкость образует защитную сферу, которая спасает от газов и дыхательного оружия.
4 - Дымящаяся жидкость угольного цвета в металлическом флаконе. Даёт сопротивлению холоду.
5 - Маслянистая жидкость сливового цвета и на вкус такая же. Залита в глиняный кувшинчик, размером с маленький стакан. Изменяет внешний вид владельца по его желанию (сходно заклятью полиморфа).
6 - Зеленый порошок, который нужно разводить водой, хранится в емкости из полой кости. Делает невидимым.

После сотен сессий настолок я обнаружил три столпа приключений, которые всегда мотивируют персонажей в 100% случаев:
- Жадность
- Любопытство
- Месть
Вот и все. Другого 100% мотивирующего фактора не существует. Некоторые персонажи движимы необходимостью помочь другим, но большинство — нет.

Если вы сможете объединить все три вещи одновременно, вы мгновенно заставите игроков спешить навстречу к вашему приключению.
Не просите игроков спасти девушку, попавшую в беду. Вместо этого:
Затем посмотрите, как они спешат отправиться в приключение как можно скорее.
Вы не можете давать игрокам слишком много золота или магических предметов, иначе это нарушит баланс игры и повысит их ожидания в следующий раз. Но если вы не соблазните их достаточным количеством золота или магических предметов, тогда они не захотят идти за этим.
Немного мести имеет большое значение, а слишком сильная месть может привести к тому, что ваши персонажи сойдут с ума.
Например, небольшая месть — это позволить воришке украсть их кошелек с монетами и повести их в погоню. Слишком большая месть — это украсть любимый предмет героя, убить его любимого НПС или проклясть его так сильно, что это сделает персонажа практически неиграбельным.
Убедитесь, что отомстить действительно достижимо. А когда они отомстят, пусть наслаждаются этим.
Любопытство всегда полезно почти в каждой встрече.
Секрет любопытства заключается в том, чтобы не выдать секрет. Пусть герои разберутся во всем сами. Дайте подсказки, не раскрывая секрета. И постарайтесь, чтобы обнаруженное любопытство привело к другому источнику любопытства.
Например, у главаря бандитов есть карта, ведущая в лес, но не написано куда. Это ведет к скрытому входу в подземелье, ведущему к запертому сундуку, содержащему древний артефакт, который может идентифицировать только волшебник-затворник в соседнем городе, что приводит к загадочному исчезновению волшебника….