January 7, 2020

Очередная консольная RPG (не круто), часть 2

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

В строчке switch (tavern()) используется функция tavern, которую я написал в предыдущей части. Вот она:

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

На этой картинке видно строчку har();, это функция, которая просто выводит информацию об игроке и выглядит она вот так:

В запущенном виде это выглядит так:

Если ввести 1, то ничего не произойдет, потому что функция torgO, которая должна отвечать за оружейный магазин, сейчас пустая. Нужно ее описать, но для начала я хочу нарисовать оружейника. Я набросал его в паинте:

Не впечатляет, соглашусь. Да и рисунки в консоль вроде нельзя вставлять. Поэтому я пойду другим путем. Я конвертирую этот рисунок в ASCII картинку (это рисунок символами) с помощью первого попавшегося сайта.

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

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

int n в скобках в первой строчке как раз и говорит о том, что при вызове функции нужно будет отправлять число. Торговец оружием рисуется при выборе числа 1, как видно из рисунка, поэтому его изображение будет просто вызвать строчкой otr(1). Круто же)

Далее займемся функционалом. При вызове функции объявляется переменная vyb целочисленного типа, которая будет хранить число, которое выбрал игрок. Далее в цикле (я его обрезал намеренно, чтобы не показывать весь код сразу, а по частям все объяснить) очищаем консоль командой system("cls"), рисуем торговца (назовем его Михаилом для краткости), приветствуем игрока по имени, даем несколько вариантов на выбор и считываем число с клавиатуры.

Если мы выбрали пункт "Купить", то бишь ввели 1, то нужно объявить еще одну переменную для выбора vybor (я говорил, что без кучи переменных я не умею). Далее цикл. В цикле очищаем консоль, рисуем Михаила.

Ух, после отрисовки интересно. Нужно вывести оружие. Приготовься, может быть сложно. А может и не сложно хз.

Это цикл for. i = 0 это начальное значение, i < 3, это условие, которое закончит цикл, если перестанет быть верным, i++ это команда, которая должна выполняться, когда цикл один раз выполняется, в нашем случае i увеличивается на 1.

Когда цикл проходит первый раз, i равно нулю. То есть в единственной команде в цикле вместо i будет подставляться 0. Выглядеть это примерно так:

cout << 0 + 1 << ". " << ar[0].name << " | +" << ar[0].uron << " | " ar[0].stoim << " денег\n";

\n это символ переноса строки. Вот характеристики оружия в нулевом элементе массива:

В итоге выведется следующая строка: "1. Палка | +30 | 50 денег"

Потом i увеличится на 1, и пройдет все то же самое, только уже для цифры 1, и так далее, пока цикл не закончит работу.

После того, как цикл прекратит работу, мы выведем еще одну строчку, в которой будем пункт "назад". Это i + 1, потому что мы каждый раз выводили i + 1, последний пункт был 3, а значит i было равно 2. После последнего прохода цикла i увеличился на 1, стал 3, и условие i < 3 больше не верно, поэтому цикл прекратил работу. А мы выводим 3 + 1 пункт меню с надписью "назад".

Далее выводим характеристики героя и проверяем, если игрок выбрал пункт "Назад", то команда break прерывает текущий цикл и мы возвращаемся обратно в "купить/продать/уйти".

Далее выводим разделитель, чтобы было красиво (относительно), и проверяем, а хватает ли у игрока денег? Если нет, то Михаил говорит об этом. else означает "иначе", а "иначе" в данном случае означает, что у игрока хватает денег. Михаил хвалит нашу покупку, у нас отнимаются деньги и опять функция.

dov(ar[vybor - 1].id) выглядит очень сложно и непонятно, я так считаю. Но мы всего-лишь отправляем id выбранного оружия в функцию, которая добавляет предмет в инвентарь, которая выглядит вот так:

Здесь все довольно просто. Мы перебираем все ячейки инвентаря, пока не найдем пустую (пустые помечены нулем), и заменяем 0 на id предмета.

Вот так выглядит все, что происходит, если выбрать первый вариант:

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

Михаил говорит, что готов купить все, что угодно, потому что сейчас не очень хочется заниматься вещами вроде "оружейник не купит кость или кусок протухшего мяса"

Встречайте еще одну функцию! invS! Она выводит весь инвентарь и возвращает номер последнего элемента, рассмотрим ее чуть позже.

Далее выводим (количество предметов в инвентаре)+1 пункт меню "назад". Считываем с клавиатуры число, и если выбран пункт "назад", то прекращаем цикл и снова возвращаемся в "купить\продать\уйти". Снова выводим разделитель, прибавляем игроку денег и в элемент массива с инвентарем, в котором лежал id проданного предмета, записываем 0 (0 означает, что ячейка пустая). Далее sortI, эта функция сортирует инвентарь.

Вот так выглядит общая картина:

Теперь рассмотрим invS и sortI.

Для начала sortI. Здесь все завязано на двух переменных emp и cur. В emp программа записывает первую найденную пустую ячейку. В cur же записывается первая найденная после emp НЕпустая ячейка. Потом emp и cur меняются местами, этот цикл проходит, пока cur < 100.

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

Цикл в этой функции работает, пока не найдем пустую ячейку, именно поэтому его сначала нужно было отсортировать, убрав все непустые ячейки влево. В дело вступает мой любимый switch. Здесь он интереснее. Деление здесь происходит без остатка, то есть 32/10 = 3. Цикл проверяет pl.inv[y-1] / 10 означает, что мы проверяем десяток текущего предмета. Если результат деления равен 0, то это бесполезная хрень. В name кладем название, в stoim кладем стоимость и выводим это все в правильном порядке. Если 1, то чуть интереснее. ar[pl.inv[y-1] % 10], это надо объяснить. pl.inv[y-1], y-1, потому что y на 1 больше, чем надо из-за того, что отсчет элементов в массиве начинается с 0, а не с 1. % 10 означает остаток от деления на 10. Например, у элемента с номером 0 id 30. 30 % 10 = 0, поэтому из id можно получить номер элемента. Дальше все, как обычно. Распихиваем информацию по строковым переменным и выводим. С броней все точно так же.

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

Теперь можно показать Михаила полностью:

Если кто-то заметил, то тут есть условия while (1==1), что в переводе на русский означает "Выполняйся, пока 1 равен 1". Это сделано потому, что команды для выхода из цикла break уже присутствуют в этих циклах.

Теперь пара скриншотов)

Консоль пришлось растянуть

Надо что-то купить

Палка? Ну, у меня только на нее денег и хватит, беру!

Теперь надо посмотреть инвентарь..

Ух ты, палка и правда тут! Только зачем она мне. Пойду опять к Михаилу.

Отлично, тогда купи у меня эту палку!

Отлично, деньги на месте! Нужно еще раз проверить инвентарь.

Пусто.. Как и должно быть.

Надеюсь, тебе понравилось! Вступай в чат https://t.me/markovachat