35 килобайт минифицированного кода на обычном JavaScript, семь городов, пустоши, радиоактивные гекконы, съедобные кактусы, встречные караваны и бандиты. Что это? Это небольшая игра, которая запускается в браузере. Ее принципы довольно просты для повторения и в самой примитивной версии ее можно воссоздать, наверное, на любом устройстве, если там есть устройство вывода и генератор случайных чисел. Но сегодня я хочу рассказать, как я реализовал ее для современных браузеров.

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

Весь сеттинг, мир и логику можно модифицировать, как вам вздумается — исходный код и графика распространяется как public domain, то есть без ограничений на копирование и использование.



Возможности игры


Ваши следопыты могут найти съедобный кактус или довоенные консервы. В пустыне можно найти трупы других путешественников, с которых можно поднять немного денег. У встречных караванов можно купить еды или браминов, а также нанять людей. А еще к вам могут присоединиться встречные бродяги, а иногда — даже бандиты, если вы поразите их своей харизмой. Шутка. На самом деле харизмы в игре пока нет, она эмулируется рандомом.

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

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

Механика этой игры довольна проста, а её графические возможности — это диалоги, индикаторы и движение по карте мире. Ее сила — в магии текстовых игр, которые способны с помощью слов описывать самые невероятные приключения.

Основная идея и логика программы


Базовая идея игры очень проста — мы запускаем бесконечный цикл, внутри которого выполняется четыре базовых операции:

  1. Движение к заданной точке
  2. Отсчет дней
  3. Потребление еды
  4. Проверка на вероятность для события, которое нас ждет в пустоши

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

Как это происходит? Очень просто — каждое событие просто меняет числовые параметры каравана или мира, а затем сообщает об этом в лог. И вот тут возникает магия — параметры могут быть одними и теми же, но сообщать можно о совершенно разных причинах. Минус несколько единиц еды? Это могут быть нападения крыс, выпадение радиоактивных осадков или голодных бродяг. Плюс несколько единиц еды? Значит, ваши люди нашли съедобный кактус, раскопали в придорожных руинах довоенные консервы или нашли на дороге замечательные кожаные сапоги с мягкой подошвой.

Первая версия, с которой я начал экспериментировать, выглядела чистой иллюстрацией описанного алгоритма:



Я сделал этот прототип как ремейк игры про орегонский караван из этого туториала.

Одномерный прототип — караван для js13kGames


Игра из туториала, которую я нашел, была одномерной — караван выходил из одной точки и приходил в другую. В пути происходили случайные события, встречи с бандитами и торговцами.



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

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

Список изменений
  1. Многоразовое путешествие — игра не прекращается с достижением цели
  2. Двухмерная карта мира и города
  3. Другой сеттинг мира и никакой дизентерии
  4. Бандиты могут вступать в переговоры и наниматься
  5. Добавлены товары, которые автоматически продаются и покупаются при достижении города
  6. Модульная система — логика на базе плагинов и наборы событий в отдельных файлах


Движок каравана и архитектура


Игра, как уже было сказано, сделана на чистом JavaScript без использования сторонних библиотек (вы можете сами добавить их, если сочтете нужным). Для отображения карты мира и интерфейса используется обычный HTML и CSS. Чтобы изменять их, используются базовые операции с DOM и классическая операция document.getElementById

Пример отображения количества игроков в караване
this.view = {}; // объект для хранения элементов DOM
this.view.crew = document.getElementById('game-stat-crew'); // находим элемент при запуске игры
// ...
this.view.crew.innerHTML = world.crew; //  записываем число людей в караване как обычный html 


WorldState — модель мира


Мир в игре — это класс WorldState. Он хранит в себе все важные параметры и не содержит никакой логики. Логику мы привяжем потом, за счет плагинов.

function WorldState(stats) {
    this.day = 0;           // текущий день, с десятичными долям
    this.crew = stats.crew; // количество людей
    this.oxen = stats.oxen; // количество быков
    this.food = stats.food; // запасы еды
    this.firepower = stats.firepower; // единиц оружия
    this.cargo = stats.cargo;   // товаров для торговли
    this.money = stats.money;   //деньги

    // лог событий, содержит день, описание и характеристику
    //  { day: 1, message: "Хорошо покушали", goodness: Goodness.positive}
    this.log = [];

    // координаты каравана, пункта отправления и назначения
    this.caravan = { x: 0, y: 0};
    this.from = {x: 0, y: 0};
    this.to = {x: 0, y: 0};

    this.distance = 0; // сколько всего пройдено

    this.gameover = false;  // gameover
    this.stop = false;    // маркер для обозначения того, что караван стоит
    this.uiLock = false; // маркер для блокировки интерфейса
}

Game — создание мира и игровой цикл


Игровой цикл запускается и управляется объектом Game. Этот же объект создает мир. Обратите внимание на поле plugins — по умолчанию это пустой массив. Game ничего не знает о плагинах, кроме двух вещей — у них должна быть функция инициализации init(world) и функция обновления update.

Game = {
    plugins: [],  // генераторы событий, 
};

Game.init = function () {
    // создаем мир по стартовому состоянию которое хранится в отдельном файле
    // в объекте StartWorldState в директории data
    this.world = new WorldState(StartWorldState);

    var i;
    for (i = 0; i < this.plugins.length; i++) {
        this.plugins[i].init(this.world);
    }
};

// добавление плагинов
Game.addPlugin = function (plugin) {
    this.plugins.push(plugin);
};

// игровой цикл
Game.update = function () {
    if (this.world.gameover) return; // никаких действий
    var i;
    for (i = 0; i < this.plugins.length; i++) {
        this.plugins[i].update();
    }
};

Game.resume = function () {
    this.interval = setInterval(this.update.bind(this), GameConstants.STEP_IN_MS);
};

Game.stop = function () {
    clearInterval(this.interval);
};

Game.restart = function () {
    this.init();
    this.resume();
};

Для запуска новой игры надо вызвать функцию Game.restart. Но прежде чем это произойдет, надо добавить какой-нибудь плагин — иначе ничего не будет происходить, у нас просто будет вхолостую работать игровой цикл.

Ешь, живи, двигайся — CorePlugin


Самые базовые действия каравана — перемещение, отсчет времени и потребление пищи — реализованы в объекте CorePlugin:

исходный код CorePlugin
CorePlugin = {};

CorePlugin.init = function (world) {
    this.world = world; // запоминаем world
    this.time = 0; // общее время с начала игры, в миллисекундах
    this.dayDelta = GameConstants.STEP_IN_MS / GameConstants.DAY_IN_MS; // сколько дней в одном шаге игру
    this.lastDay = -1;  // отслеживаем наступление нового дня
    this.speedDelta = Caravan.FULL_SPEED - Caravan.SLOW_SPEED; // разница между полной и минимальной скоростью
};

CorePlugin.update = function () {
    if (this.world.stop) return; // если стоим - никаких изменений
    this.time += GameConstants.STEP_IN_MS; // увеличение времени
    this.world.day = Math.ceil(this.time / GameConstants.DAY_IN_MS); // текущий день, целый

    // Движение каравана в зависимости от того, сколько дней прошло
    this.updateDistance(this.dayDelta, this.world);

    // события связанные с наступлением нового дня
    if (this.lastDay < this.world.day) {
        this.consumeFood(this.world);
        this.lastDay = this.world.day;
    }
};

// еда выдается один раз в день
CorePlugin.consumeFood = function (world) {
    world.food -= world.crew * Caravan.FOOD_PER_PERSON;
    if (world.food < 0) {
        world.food = 0;
    }
};

// обновить пройденный путь в зависимости от потраченного времени в днях
CorePlugin.updateDistance = function (dayDelta, world) {
    var maxWeight = getCaravanMaxWeight(world);
    var weight = getCaravanWeight(world);

    // при перевесе - Caravan.SLOW_SPEED
    // при 0 весе - Caravan.FULL_SPEED
    var speed = Caravan.SLOW_SPEED + (this.speedDelta) * Math.max(0, 1 - weight/maxWeight);

    // расстояние, которое может пройти караван при такой скорости
    var distanceDelta = speed * dayDelta;

    // вычисляем расстояние до цели
    var dx = world.to.x - world.caravan.x;
    var dy = world.to.y - world.caravan.y;

    // если мы находимся около цели - останавливаемся
    if(areNearPoints(world.caravan, world.to, Caravan.TOUCH_DISTANCE)){
        world.stop = true;
        return;
    }

    // до цели еще далеко - рассчитываем угол перемещения
    // и получаем смещение по координатам
    var angle = Math.atan2(dy, dx);
    world.caravan.x += Math.cos(angle) * distanceDelta;
    world.caravan.y += Math.sin(angle) * distanceDelta;
    world.distance += distanceDelta;
};

// регистрируем плагин в игре
Game.addPlugin(CorePlugin);


Тут все элементарно. Сначала при запуске игры у нас вызывается init, который позволит сохранить ссылку на модель мира. Затем в игровом цикле у нас будет вызываться update, который будет менять мир к лучшему, как любят говорить персонажи из сериала «Силиконовая долина». Шутка — меняться мир будет во все стороны.

Наш базовый плагин отсчитывает время в миллисекундах, переводит их в дни, а затем обновляет дистанцию и запасы еды. В принципе, объект плагина просто должен содержать функции init(world) и update(), а делать он может что угодно. Можно даже просто вызывать какую-нибудь другую игру на HTML5 или создавать диалоговое окно.

Чтобы подключить плагин, надо добавить его код между определением объекта Game и первым вызовом Game.restart(). Примерно так, как это сделано сейчас в index.html:

<script src="js/Game.js"></script>

<!-- плагины -->
<script src="js/plugins/CorePlugin.js"></script>

<!-- запуск игры -->
<script>
    Game.restart();
</script>

Итак, как сделать игру про караван


Если вы опытный программист — вы, безусловно, можете реализовать подобную игрушку на любом языке и графическом уровне, просто отталкиваясь от самой идеи «цикл, в котором происходит перемещение и рандомный выбор из массива событий». Думаю, прекрасно получится даже игра для bash, тем более, что недавние публикации показывают, что там есть весьма интересные графические возможности.

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

Существующие плагины можно отключать (убирая их исходный код из index.html или закомментировав строку с Game.addPlugin(SomePlugin) в конце их кода). Они ничего не знают друг о друге и просто меняют модель мира или интерфейс игры.

Ну и последний вариант, для писателей — просто открывать файлы в директории data и редактировать описания событий и константы. Хотя это те же JavaScript-исходники, они довольны просты для изменений. Особенно тексты. Чтобы доказать это, я вкратце расскажу, как устроены другие плагины в текущей версии.

Случайные события


Все примитивные случайные события лежат в файле data/RandomEvents.js в переменной RandomEvents в таком формате:

var RandomEvents = [
    {
        goodness: Goodness.negative,
        stat: 'crew',
        value: -4,
        text: 'На караван напал смертокогть! Людей: -$1'
    },
    {
        goodness: Goodness.negative,
        stat: 'food',
        value: -10,
        text: 'Кротокрысы на привале сожрали часть еды. Пропало пищи: -$1'
    },
  {
        goodness: Goodness.positive,
        stat: 'money',
        value: 15,
        text: 'У дороги найден мертвый путешественник. На теле найдены монеты. Денег: +$1'
    },
    {
        goodness: Goodness.positive,
        stat: 'crew',
        value: 2,
        text: 'Вы встретили одиноких путников, которые с радостью хотят присоединиться к вам. Людей: +$1'
    },

Объекты случайных событий содержатся в фигурных скобках. В этом примере я привел только четыре объекта, но вообще их число может быть каким угодно. Только имейте в виду, что при увеличении числа событий вероятность выпадения конкретно отдельного из них уменьшается.

Первое поле — goodness- означает позитивную, негативную и нейтральную окраску сообщения в логе. Второе поле — stat — содержит название параметра WorldState, который должен меняться. Value — это среднее значение для изменения этого параметра. Последнее поле — должно содержать любой произвольный текст, описывающий произошедшее. Вместо символом $1 в текст будет подставлено реальное изменение параметра, которое выпадет в игре.

Случайные события проверяются на выпадение в объекте RandomEventPlugin и радуют взгляд игрока в логе:



Последнее примечание: в RandomEvents.js вы найдете переменную с константой вероятности выпадения случайного события. Она задается как среднее число событий на один игровой день каравана. Когда я экспериментировал с разными значениями, то обнаружил, что слишком много случайных событий, на которые нельзя никак повлиять, начинают дико раздражать. Отсутствие интерактива — это главный минус этих простых событий. Вот почему я почесал голову и решил сделать универсальный модуль диалогов, который можно вызывать из других плагинов.

Как написать или отредактировать диалог


За диалоговую систему отвечает объект DialogWindow. Если вы заглянете в его исходный код, то увидите мутанта, который находит в HTML-коде нужный div-элемент и привязывает к нему общий обработчик кликов мышкой. Идея заключается в том, что когда мы просим этот объект показать нам новый диалог, мы передаем ему массив наших диалогов. И обработчик нажатия на конкретный выбор описывается в конкретном диалоге в таком формате:

var DeathDialogs = {
    "start": {
        icon: "images/pic_death.jpg", // ссылка на url картинки
        title: "Погибший в пустоши", // заголовок диалога
        desc: "",                                // статический текст диалога
        desc_action: function (world, rule) { // функция для создания вычисляемого текста диалога
            var desc = " Причина смерти: "+rule.text+". Вы сумели пройти "+Math.floor(world.distance) + " миль и накопить "+Math.floor(world.money) + " денег";
            desc += "Может быть, следующим караванщикам повезет больше?"
            return desc;
        },
        choices:[  // массив выборов
            {
                text: 'Начать новую игру', // текст на кнопке
                action: function () { return "stop"; }  // функция, возвращающая тег следующего диалога
            }
        ]
    },
};

В диалогах смерти только один вариант, описанный как поле «start». Но таких вариантов может быть бесконечно много. К примеру, в диалогах бандитов я реализовал 12 развилок. Как происходит переход между ними? Наш универсальный объект DialogWindow при вызове функции show сохраняет у себя список переданных диалогов и показывает тот, который определен в поле «start».

При отображении очередного диалога его массив choices отображается как набор кнопок, в атрибуты которых записывается номер выбора. А все функции action из choices записываются во внутренний массив dialogActions. При клике мышкой на кнопке выбора универсальный обработчик определяет номер функции в dialogActions и вызывает ее, попутно передавая два аргумента, которые мы решили использовать в этом диалоге. Таким образом, в диалогах с бандитами функция action в конкретном choice может принимать состояние мира (world) и описание текущих бандитов (bandits). А в диалогах к другим плагинам — другие параметры. Да можно и вообще без них, особенно, если смысл выбора — просто закончить диалог, как при геймувере.



Чтобы диалог закончился и игрок вернулся к карте мира, надо, чтобы функция action в объекте choice возвращала один из зарезервированных тегов «finish»,«exit»,«stop». Вообще смысл этой функции в том, чтобы возвращать имя следующей развилки. Но до этого заветного return-a можно и порой нужно вставить любую логику, любые вычисления, которые позволят выбрать следующую развилку — «run», «fight» или, быть может, даже «love».

Как вызвать диалог из плагина


В любой момент времени в update любого работающего плагина можно вызвать диалог следующим образом:

    // ... где-то в недрах update у объекта-плагина
    // останавливаем караван, аналог паузы
    world.stop = true; 
   // просим показать диалог с набором развилок из DeathDialogs
   // в развилки будут передаваться аргументы world и rule
    DialogWindow.show(DeathDialogs, world, rule, this);

Также в плагине должна быть реализована функция onDialogClose — этот коллбэк будет вызываться после закрытия диалога. Пример из плагина, определяющего наступление смерти:

DeathCheck.onDialogClose = function () {
    Game.restart();
};

Краткое описание существующих плагинов


В текущей версии игры используются следующие плагины:

Map2DPlugin — перемещение каравана по карте. Поиск городов, которые задаются в index.html как обычные div с параметрами top и left. Здесь же определяется прибытие в город и происходит автоматическая торговля.

ShopPlugin — генерация случайных встречных караванов или других торговцев. Позволяет купить еду, браминов и нанять наёмников. Или ничего не покупать и пойти дальше.

BanditPlugin — встречи и диалоги с бандитами. Примерно на середине этого плагина я понял, что с идеей сделать простой туториал я погорячился. Простого не получилось, извините. Бандиты могут наняться к вам, а если они умирают с голоду — попросят принять их бесплатно, если вы откажете при найме за деньги.

DropPlugin — плагин перегруза. В прототипе из туториала про орегонский караван игра сама автоматически сбрасывала вещи — сначала оружие, а потом еду. Это было не очень комфортно и вызывало недоумение — как так-то? Ведь с оружием можно добыть еду, а «жареным мясом нельзя убить врага» (с) один известный стрим по Fallout 4. Так что я решил сделать диалог, в котором ты просто выбираешь, от чего избавиться.

DeathCheck — плагин проверки на смерть. Это пока очень простой плагин, и к нему наверняка могут быть вопросы. К примеру, почему люди умирают сразу, когда заканчивается еда? Ну, предлагаю ответить на этот вопрос самостоятельно — или подождать следующей версии, если все пойдет хорошо.

WorldViewPlugin — интерфейсный плагин. Он просто обновляет интерфейс, показывая текущие параметры мира. Возможно, эта идея покажется кому-то странной — самостоятельный объект интерфейса, который отслеживает в цикле обновления изменения переменных. Но зато благодаря этой странной идее мы избавились от многочисленных updateUi и получили независимость между блоками разной логики.

Небольшие советы по текущей игре и балансу


Жизненно важный параметр сейчас — количество еды. Пополнить ее можно при встречах с другими караванами — если они происходят, следует закупаться по максимуму. Конечно, разумно было бы добавить покупку и в городах, но будем считать, что пока все они страдают от недостатка еды.

Второй жизненно важный параметр — количество людей в караване. Они должны быть. Если всех людей выбивают — игра заканчивается.

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

Ссылки и дистрибутивы


Я использовал графику с лицензией Creative Common 0 с ресурсов pixabay.org и opengameart.org, так что и графика, и код распространяется на этих условиях — свободное копирование и использование, без каких-либо обязательств.

Исходный код можно взять с GitHub или скачать zip-архивом отсюда. Первый вариант предпочтительнее, так как чаще обновляется.

Для тестирования даже на локальном компьютере достаточно открыть index.html в браузере — там не используются функции, которым обязательно требуется сервер.

Живой билд игры можно потестить здесь. Верстка рассчитана на обычные мониторы, не на мобильные экраны.

Комментарии (71)


  1. Akuma
    18.09.2017 21:05
    +2

    В целом круто, только я несколько раз погибал от голода, но при этом еды купить было просто негде. Надо бы какой-то баланс добавить.

    Так же смертокогти убивали тупо всех людей, хотя у меня куча еды, оружия и бабла.


    1. Zoolander Автор
      18.09.2017 21:11

      да, справедливо
      магазины в городах добавятся

      смертокогти, как и все остальные причины смертей, думаю, надо выносить из чисто рандомных событий в более управляемые события. Это наследие «орегонского каравана», там люди вообще умирали от дизентерии


      1. bond1768
        18.09.2017 23:04
        +1

        Вообще ништяк идея. В городе надо магазины сделать что бы можно было самому баланс настраивать — что продать что докупить.


    1. Viacheslav01
      19.09.2017 11:15

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


    1. findoff
      19.09.2017 11:32
      +1

      Добавил поедание браминов…
      https://habrahabr.ru/post/336724/#comment_10423496


      1. Zoolander Автор
        19.09.2017 11:37

        спасибо, вечером посмотрю на рабочей машине


      1. kasperos
        19.09.2017 14:04

        Глюк: если количество людей таково что количество еды после потребления в день становится равно 0, при имеющемся запасе браминов караван погибает от голода.


        1. findoff
          19.09.2017 14:15

          В коде автора 0 еды = все умерли.
          В теории поправил, уменьшив допустимое кол-во съедаемой еды до забивки браминов до (имеющегося-1).
          Но вообще думаю если развивать тему, то надо перерабатывать многое.


  1. vintage
    18.09.2017 21:29
    +6

    В гитхабе можно создавать релизы и они будут автоматом упаковываться в архив.


  1. gwyn-art
    18.09.2017 21:39
    +1

    Купить 20 еды за 35 или 65 долларов. Это странно.


    1. Zoolander Автор
      18.09.2017 22:46

      Без объяснения — да )
      Объяснения можно придумать, скажем, разные сорта
      Подумаю, как компактно и логично ввести объяснения в следующем патче.


  1. vintage
    18.09.2017 22:18
    +1

    Почему нельзя закупиться еды в городе?


    1. Zoolander Автор
      18.09.2017 22:43

      пока не реализовано, города — это просто точки, там ничего нет, кроме координат
      добавлю на следующей неделе


    1. danl
      18.09.2017 22:45
      +1

      да, с едой беда


  1. Legion21
    19.09.2017 00:16
    +1

    Ностальгия по первому фолычу… Желаю успехов и дальнейшего развития проекта!


  1. A1fobos
    19.09.2017 00:29
    +10

    На дороге найдены хорошие довоенные кожаные сапоги. Запасы еды: +3


    1. hdfan2
      19.09.2017 07:54
      +7

      image


  1. TheShock
    19.09.2017 02:23
    +1

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

    Жанр, мне кажется, больше всего похож на Космические Рейнджеры, некоторые идеи можно почерпнуть оттуда. Для начала оттуда следует взять экономику — браминов, еду, оружие, товары и людей можно покупать в городах за разные цены. При случайных встречах можно продать подороже и купить подешевле. Цены меняются от количества товара — продаешь пачками и цена падает, покупаешь пачками — цена растет. Появляется смысл следить за ценами, строить разные маршруты, покупать слухи на счет ходовых товаров, думать, стоит ли продавать еду, чтобы купить людей, сдавать весь товар или часть оставить для следующего города.

    А еще, кажется, брамины не едят. Может, стоит добавить возле количества еды ее дельту за день?


    1. TheShock
      19.09.2017 02:28

      Это, кстати, решит текущую проблему с едой и людьми, когда от игрока, по сути, ничего не зависит


      1. TheShock
        19.09.2017 02:43

        Мой результат


        1. TheShock
          19.09.2017 03:06
          +1

          Можно сказать, что я её прошёл?


          1. lostpassword
            19.09.2017 08:17
            +3

            Мне кажется, для этого везде должно быть по шесть девяток.


          1. Zoolander Автор
            19.09.2017 11:05

            расскажите, как вы этого добились?
            это из-за автоматической торговли, которая позволяет не отходя от города набивать деньги? Этот прокол я поправлю, а вашим достижением — горжусь


            1. kasperos
              19.09.2017 13:07
              +1

              Побегал по точкам, возвращаться обратно в город не догадался, но и без этого все получилось.
              Начало игры между соседними городами.
              Активно создаем по возможности запас пищи (первый приоритет, так как по достижении 0 все пропало, хотя вроде как я понял пофиксили поеданием волов).

              Не хватает очень множителя, ибо очень вспоминается в процессе покупки пищи волов и прочего молодость.

              Перед тем как зависнуть (видимо попал на момент обновления), накопил 1500 браминов, 1,5 мегаденег, центнер людей.
              Еще идеи:
              От пропорции людей/волов имеет смысл менять скорость каравана, так как если один человек будет вести 1000 волов, то высокий шанс их растерять, а большое количество людей сказывается на скорости поедания еды, а волы как я понял еду добывают по пути.

              Классификация людей:
              Наемники — универсал охотник/загонщик но требует периодической зряплаты, на то он и наемник.
              Охотник — плохо управляется со скотом но хорошо отражает нападения бандитов/хищников.
              Загонщик — хорошо управляется со скотом но плохо помогает в обороне.
              Пропорция вознаграждения должна зависеть от дистанции между городами, так как пройти караваном наискосок через всю карту, и выйти за забор и вернуться назад разные риски.


            1. vlukanichev
              19.09.2017 13:41

              image
              Пожалуй да, даже без стояния в одном городе можно набить стартовый капитал между двумя близ стоящими городами. И дальше можно бегать из одного противоположного угла в другой. Открыв консоль для того чтобы не ломать мышку кликами по 1000 раз при покупках можно получить что то такое. Врядли тут можно проиграть. Было бы неплохо добавить возможность покупать «оптом». Или, как вариант, дать всем встречающимся магазинам лимит по товарам.


    1. findoff
      19.09.2017 09:42

      Еще проще: нажимаем на другой город, выходим и нажимаем обратно… $$$


      1. vlukanichev
        19.09.2017 11:03

        Еще проще: тоже самое только никуда выходить не надо. Можно просто кликать в тот город в котором стоишь получая каждый раз по $600.


        1. findoff
          19.09.2017 11:31
          +1

          Поправил(пул реквест послал) и добавил поедание браминов от голода >:Fl)


          https://sw.doomcalc.com/nukecaravan/


          1. Zoolander Автор
            19.09.2017 15:23

            там хорошая идея и рабочий код
            я сделал только, что уникальный идентификатор последнего города — это его координаты. Это упрощает модель.


  1. iSergios
    19.09.2017 07:47
    +4

    Гм, идем, значит, мы караваном в 35 человек, еды 5000+, браминов 60+, денег 20к+, и тут на тебе:

    День 155: На дороге найдены хорошие довоенные кожаные сапоги. Запасы еды: +3

    А еще очень странно, когда 10-20 здоровых (или не очень) мужиков дохнут в пустыне с голоду при полусотне живых браминов рядом :)

    За идею и реализацию большой респект :)


    1. Zoolander Автор
      19.09.2017 11:08

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


      1. ikovrigin
        19.09.2017 13:19
        -3

        10-20 здоровых мужиков будут жарить быков… разрешите им в городе брать баб в отряд.


        1. ikovrigin
          19.09.2017 13:35
          -2

          Похоже некоторые не осознали всей глубины игры с добавлением баб… это же песочница игрок может делать что хочет. Могут бабы жарить быков, могут мужики жарить баб, а могут даже быки жарить баб, тут все зависит от фантазии, только в зависимости от уровня фантазии нужно будет повышать возрастные ограничения.


      1. kasperos
        21.09.2017 07:30
        +1

        Занятная ситуация, караван шел, шел, ели быков потихоньку, когда съели последнего: караван завис вместе с браузером.
        Кстати а чем собственно они там заниматься будут когда последнего быка съедят или потеряют, а «магазина» с быками не попадется.


        1. Zoolander Автор
          21.09.2017 14:57

          должны умереть с голода
          посмотрю, в чем баг


        1. Zoolander Автор
          21.09.2017 15:24

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


          1. TheShock
            21.09.2017 15:31
            +1

            Так в мид-гейме и енд-гейме пропадает смысл покупать еду — лучше закупить быков побольше)


            1. Zoolander Автор
              21.09.2017 16:01

              и это внезапно реалистично! )
              пираты Карибского моря и Тихого океана брали с собой галапагосских черепах, как живые консервы


  1. Milfgard
    19.09.2017 10:16
    +1

    Чёрт, какая может крутая инди-игра получиться.
    Жалко только, Беседка за вами может прийти — стоит чуть-чуть начать косить под Фаллаут.


    1. johnnymmc
      19.09.2017 10:44
      +1

      Да, интересненько. Отдалённо напоминает тёплвй ламповый Oregon Trail. Было бы клёво добавить сюжетностей, NPC со своими вызывающими сопереживание историями и возможностью осмысленного общения, всего такого, добавить какой-то атмосферный арт и может весьма уютная штука выйти.


      1. Zoolander Автор
        19.09.2017 11:44

        приятно увидеть человека, знакомого с Oregon Trail!

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

        Туториал с простым караваном, на который я ссылаюсь, в свою очередь ссылается на Oregon Trail. Так что это дедушка и этого каравана )


        1. johnnymmc
          19.09.2017 13:09
          +1

          Взаимно приятно :-) Вообще Oregon Trail Deluxe 1992-го года прекрасно скачивается по первой же ссылке из Гугла (myabandonware) и легко запускается через CrossOver на Маке. Провёл за ним в обнимку с девушкой несколько невероятно уютных вечеров :-) (а вот Oregon Trail II, например, уже показалась черезмерно усложнённой). Подумал тогда что надо будет как-нибудь написать что-то подобное. Рад, что в опенсорсе появился такой проект. Но мне кажется надо будет только всё-таки слегка усложнить-детализировать игровую модель, увеличить мир и добавить сюжетную составляющую и может выйти что-то очаровательное. Очень здорово, что в основу заложена идея отделения данных от движка, так что в будущем не-программисты смогут достаточно легко вносить вклад в обогащение игрового мира.


        1. johnnymmc
          19.09.2017 13:39

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


    1. Zoolander Автор
      19.09.2017 11:03

      спасибо за оценку
      лор придется править, если так


  1. TheRabbitFlash
    19.09.2017 10:59

    35 кб это много или мало? Меня зацепило название. Тут упор на «как можно меньше»? ) Если да, то код можно «похудеть» в 2 раза :)


    1. Zoolander Автор
      19.09.2017 11:13

      думаю, что 35 килобайт — это скорее мало, чем много
      но вы правы — в исходниках много места занимают тексты и названия функций
      я старался создать читаемый код, хотя бы для себя

      с играми на таком принципе можно смело идти на конкурс js13k — там есть что оптимизировать и сократить


      1. TheRabbitFlash
        19.09.2017 11:44

        Читаются очень здорово, согласен :)
        Я себе делал как-то тулзу, которая ищет повторяющиеся блоки в коде и дает их переименовать ручками :) некий прокачанный find&replace. В итоге код любой более-менее либы сокращается на 10-50% :)


  1. Tisar
    19.09.2017 11:01

    Брамины это что такое? и зачем они нужны?

    P.S.: в игре не помешало бы иметь справку с описанием характеристик и краткой механикой игры.


    1. Zoolander Автор
      19.09.2017 11:02
      +4

      Брамины — быки из одной малоизвестной игры про апокалипсис


      1. Geograph
        19.09.2017 14:20

        Я думал это «Член высшей жреческой касты в Индии.»


        1. Zoolander Автор
          19.09.2017 15:24

          я когда играл в Fallout, тоже улыбался над этим.


    1. Zoolander Автор
      19.09.2017 11:07

      по справке — я не думал, что эта поделка сможет выглядеть как полноценная игра
      но теперь вижу, что справку можно и нужно добавлять


      1. findoff
        19.09.2017 11:34

        Игры бывают разного размера…
        Это мелкая простая, и от того забавная на зайти и потыкать, и даже чуть дописать.


  1. theWaR_13
    19.09.2017 11:44

    Очень интересно написана сама игра. То, как работают плагины в частности. Обязательно изучу исходники потом. Спасибо большое за статью! :)


  1. jaguard
    19.09.2017 11:55
    +2

    Механика этой игры довольна проста, а её графические возможности — это диалоги, индикаторы и движение по карте мире. Ее сила — в магии текстовых игр, которые способны с помощью слов описывать самые невероятные приключения.


    Эм… А собственно, где? Где магия текста и невероятные приключения?

    Где «Вы осторожно входите в ржавые руины, бывшие когда-то огромным городом. На входе — остатки приволоченных откуда-то гаражных ворот и двое грязных оборванцев, похоже служащих стражей города; один одет в шапку-ушанку, второй — абсолютно лысый, зато имеет третий глаз..»?


    1. Zoolander Автор
      19.09.2017 16:31

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


  1. den_golub
    19.09.2017 15:18

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


    1. Zoolander Автор
      19.09.2017 15:28

      думаю, это тема следующего рассказа )


    1. TheShock
      19.09.2017 16:21

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

      Я так предполагаю, что используется requestAnimationFrame. Стоит заменить на setTimeout и все заработает.


  1. mcsimkin
    19.09.2017 15:25

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

    image


    1. Zoolander Автор
      19.09.2017 15:28

      Рад, что игра нашла опытных игроков.

      Ну, баланс можно утяжелить, увеличив вероятность встречи с бандитами с 0.1 до 1 в день для начала. Еще можно добавить событий, отнимающих еду, быков и людей.

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


  1. danl
    19.09.2017 15:33
    +2

    image

    на этом всё закончилось — OutOfMemory exception (последний FF, памяти ел всего около 1.5Гб)

    Наверное «прошёл» :)


    1. Scf
      19.09.2017 15:54

      Это сколько же человеко-клико-часов потрачено на покупку еды и браминов....


      1. danl
        19.09.2017 17:22
        +1

        ну не будет же веб-разработчик кликать 100 раз чтоб купить 2000 еды :) конечно без консоли и программных кликов (по 100 — 1000 за раз) не обошлось. Но эти клики были только в диалоге торговли и только потому, что нельзя купить сразу много. Особенно это востребовано на поздней стадии — когда надо кормить целое войско, а опта нет.


    1. Timyrlan
      19.09.2017 18:02

      даааа! сколько терпения))


    1. Zoolander Автор
      21.09.2017 16:02

      ограничили размер лога, если будет свободная минутка — попробуйте запустить свои волшебные скрипты еще раз, будет ли OutOfMemory exception?


      1. Tatikoma
        21.09.2017 17:57
        +1

        Стало лучше (правда понадобилось нажать Ctrl+F5, чтобы получить свежую версию).

        100млн браминов — работает штатно.


        1. Zoolander Автор
          21.09.2017 18:36

          спасибо


  1. Tatikoma
    19.09.2017 19:03
    +1

    Остановился на 20к браминов (закупка через xdotool click --repeat 1000 --delay 0 1).

    Количество браминов совершенно необходимо связать с количеством людей. При 20к браминов я держал при себе 30-40 людей только для того, чтобы случайно не умереть. Покупать большее количество людей нет никакого толку.

    По тактике — главное сначала скопить штук 100 браминов, запас 2000 еды и людей человек 20. Дальше просто докупаешь браминов — объем торгов растёт. Оружие — непонятно что и как работает. При значении 500 — никаких потерь в стычках с бандитами уже нет (количество людей, вероятно тоже не влияет?).

    «смертокогть» — кажется опечатка.

    Если десять раз тыкнуть на целевой город — он десять раз напишет «путешествие начинается», даже если путешествие уже в самом разгаре.

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

    В текущем формате после 5-15 минут игры — делать становится нечего. Возможно добавление мультиплеера (и связанных с ним игровых моментов) сможет дать хороший толчок.

    Непонятно что со скоростью работы самой игры. За весь игровой процесс скапливается не самый длинный текстовый лог (а нужен ли он целиковый?) + значения 8 чисел, однако при 20к браминов обсчет случайных событий занимает у меня 1-3 секунды. Товарищ чуть выше жаловался на OutOfMemory. Очевидно так быть не должно.

    В целом автор молодец. Атмосферно.


    1. Tatikoma
      19.09.2017 19:14

      Выше предлагают по аналогии с космическим рейнжерами сделать разные цены в разных городах. Мысль здравая, но сильно усложнит игру — это вообще другой жанр. Одно дело ходилка/бродилка, другое дело — экономическая стратегия. На мой взгляд нужно регулировать рост сложности игры с процессом прохождения, но другими методами. Конкретно — использование процентных ставок в событиях, учёт размера городов и прочие мелочи.

      Вообще непонятно, сам город какого размера, что я в него нормально захожу с 20к браминов? — Откуда у них каждый раз в наличии 3млн груза?

      Почему смертокогти убивают ровно 4 человек? — При некотором стечении обстоятельство они легко вырежут, скажем, 50% всей ватаги? :-)


  1. sumanai
    19.09.2017 22:25
    +1

    Разок промазал по кнопке…

    Побег
    Воодушевленные вашим отступлением, бандиты стреляют вам вслед и улюлюкают. Ваши потери: люди: 1 / браминов: 751 / eда: 10467. Денег: 5514632